| /** |
| ** |
| ** Copyright 2010, The Android Open Source Project |
| ** |
| ** Licensed under the Apache License, Version 2.0 (the "License"); |
| ** you may not use this file except in compliance with the License. |
| ** You may obtain a copy of the License at |
| ** |
| ** http://www.apache.org/licenses/LICENSE-2.0 |
| ** |
| ** Unless required by applicable law or agreed to in writing, software |
| ** distributed under the License is distributed on an "AS IS" BASIS, |
| ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ** See the License for the specific language governing permissions and |
| ** limitations under the License. |
| */ |
| |
| #include "src/pixelflinger2/pixelflinger2.h" |
| |
| #include <string.h> |
| #include <stdio.h> |
| |
| void SetShaderVerifyFunctions(GGLInterface *); |
| |
| static void DepthFunc(GGLInterface * iface, GLenum func) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| if (GL_NEVER > func || GL_ALWAYS < func) |
| return gglError(GL_INVALID_ENUM); |
| ctx->state.bufferState.depthFunc = func & 0x7; |
| SetShaderVerifyFunctions(iface); |
| } |
| |
| static void StencilFuncSeparate(GGLInterface * iface, GLenum face, GLenum func, GLint ref, GLuint mask) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| if (GL_FRONT > face || GL_FRONT_AND_BACK < face) |
| return gglError(GL_INVALID_ENUM); |
| if (GL_NEVER > func || GL_ALWAYS < func) |
| return gglError(GL_INVALID_ENUM); |
| mask &= 0xff; |
| ref = MAX2(MIN2(ref, 0xff), 0); |
| ref &= mask; |
| if (GL_FRONT == face || GL_FRONT_AND_BACK == face) { |
| ctx->state.frontStencil.ref = ref; |
| ctx->state.frontStencil.mask = mask; |
| ctx->state.frontStencil.func = func & 0x7; |
| } |
| if (GL_BACK == face || GL_FRONT_AND_BACK == face) { |
| ctx->state.backStencil.ref = ref; |
| ctx->state.backStencil.mask = mask; |
| ctx->state.backStencil.func = func & 0x7; |
| } |
| SetShaderVerifyFunctions(iface); |
| } |
| |
| static unsigned StencilOpEnum(GLenum func, unsigned oldValue) |
| { |
| switch (func) { |
| case GL_ZERO: |
| return 0; |
| case GL_KEEP: // fall through |
| case GL_REPLACE: // fall through |
| case GL_INCR: // fall through |
| case GL_DECR: |
| return func - GL_KEEP + 1; |
| break; |
| case GL_INVERT: |
| return 5; |
| case GL_INCR_WRAP: |
| return 6; |
| case GL_DECR_WRAP: |
| return 7; |
| default: |
| gglError(GL_INVALID_ENUM); |
| return oldValue; |
| } |
| } |
| |
| static void StencilOpSeparate(GGLInterface * iface, GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| if (GL_FRONT > face || GL_FRONT_AND_BACK < face) |
| return gglError(GL_INVALID_ENUM); |
| if (GL_FRONT == face || GL_FRONT_AND_BACK == face) { |
| ctx->state.frontStencil.sFail = StencilOpEnum(sfail, ctx->state.frontStencil.sFail); |
| ctx->state.frontStencil.dFail = StencilOpEnum(dpfail, ctx->state.frontStencil.dFail); |
| ctx->state.frontStencil.dPass = StencilOpEnum(dppass, ctx->state.frontStencil.dPass); |
| } |
| if (GL_BACK == face || GL_FRONT_AND_BACK == face) { |
| ctx->state.backStencil.sFail = StencilOpEnum(sfail, ctx->state.backStencil.sFail); |
| ctx->state.backStencil.dFail = StencilOpEnum(dpfail, ctx->state.backStencil.dFail); |
| ctx->state.backStencil.dPass = StencilOpEnum(dppass, ctx->state.backStencil.dPass); |
| } |
| SetShaderVerifyFunctions(iface); |
| } |
| |
| static void StencilSelect(const GGLInterface * iface, GLenum face) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| if (GL_FRONT == face) { |
| ctx->activeStencil.face = 0; |
| ctx->activeStencil.ref = ctx->state.frontStencil.ref; |
| ctx->activeStencil.mask = ctx->state.frontStencil.mask; |
| } else if (GL_BACK == face) { |
| ctx->activeStencil.face = 1; |
| ctx->activeStencil.ref = ctx->state.backStencil.ref; |
| ctx->activeStencil.mask = ctx->state.backStencil.mask; |
| } |
| } |
| |
| static void ClearStencil(GGLInterface * iface, GLint s) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| ctx->clearState.stencil = 0x01010101 * ((unsigned &)s & 0xff); |
| } |
| |
| static void ClearColor(GGLInterface * iface, GLclampf r, GLclampf g, GLclampf b, GLclampf a) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| r = MAX2(MIN2(r, 1.0f), 0); |
| g = MAX2(MIN2(g, 1.0f), 0); |
| b = MAX2(MIN2(b, 1.0f), 0); |
| a = MAX2(MIN2(a, 1.0f), 0); |
| ctx->clearState.color = (unsigned(a * 255) << 24) | (unsigned(b * 255) << 16) | |
| (unsigned(g * 255) << 8) | unsigned(r * 255); |
| } |
| |
| static void ClearDepthf(GGLInterface * iface, GLclampf d) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| // assuming ieee 754 32 bit float and 32 bit 2's complement int |
| assert(sizeof(d) == sizeof(ctx->clearState.depth)); |
| ctx->clearState.depth = (int &)d; // bit reinterpretation |
| if (0x80000000 & ctx->clearState.depth) // smaller negative float has bigger int representation, so flip |
| ctx->clearState.depth ^= 0x7fffffff; // since -FLT_MAX is close to -1 when bitcasted |
| } |
| |
| static void Clear(const GGLInterface * iface, GLbitfield buf) |
| { |
| GGL_GET_CONST_CONTEXT(ctx, iface); |
| |
| // TODO DXL scissor test |
| if (GL_COLOR_BUFFER_BIT & buf && ctx->frameSurface.data) { |
| if (GGL_PIXEL_FORMAT_RGBA_8888 == ctx->frameSurface.format) { |
| unsigned * const end = (unsigned *)ctx->frameSurface.data + |
| ctx->frameSurface.width * ctx->frameSurface.height; |
| const unsigned color = ctx->clearState.color; |
| for (unsigned * start = (unsigned *)ctx->frameSurface.data; start < end; start++) |
| *start = color; |
| } else if (GGL_PIXEL_FORMAT_RGB_565 == ctx->frameSurface.format) { |
| short * const end = (short *)ctx->frameSurface.data + |
| ctx->frameSurface.width * ctx->frameSurface.height; |
| unsigned r = ctx->clearState.color & 0xf8, g = ctx->clearState.color & 0xfc00, |
| b = ctx->clearState.color & 0xf80000; |
| const short color = (b >> 19) | (g >> 5) | (r >> 3); |
| for (short * start = (short *)ctx->frameSurface.data; start < end; start++) |
| *start = color; |
| } else |
| assert(0); |
| } |
| if (GL_DEPTH_BUFFER_BIT & buf && ctx->depthSurface.data) { |
| assert(GGL_PIXEL_FORMAT_Z_32 == ctx->depthSurface.format); |
| unsigned * const end = (unsigned *)ctx->depthSurface.data + |
| ctx->depthSurface.width * ctx->depthSurface.height; |
| const unsigned depth = ctx->clearState.depth; |
| for (unsigned * start = (unsigned *)ctx->depthSurface.data; start < end; start++) |
| *start = depth; |
| } |
| if (GL_STENCIL_BUFFER_BIT & buf && ctx->stencilSurface.data) { |
| assert(GGL_PIXEL_FORMAT_S_8 == ctx->stencilSurface.format); |
| unsigned * const end = (unsigned *)((unsigned char *)ctx->stencilSurface.data + |
| ctx->stencilSurface.width * ctx->stencilSurface.height); |
| unsigned * start = (unsigned *)ctx->stencilSurface.data; |
| const unsigned stencil = ctx->clearState.stencil; |
| for (start; start < end; start++) |
| *start = stencil; |
| start--; |
| for (unsigned char * i = (unsigned char *)start; i < (unsigned char *)end; i++) |
| *i = stencil & 0xff; |
| } |
| } |
| |
| static void SetBuffer(GGLInterface * iface, const GLenum type, GGLSurface * surface) |
| { |
| GGL_GET_CONTEXT(ctx, iface); |
| bool changed = false; |
| if (GL_COLOR_BUFFER_BIT == type) { |
| if (surface) { |
| ctx->frameSurface = *surface; |
| changed |= ctx->frameSurface.format ^ surface->format; |
| switch (surface->format) { |
| case GGL_PIXEL_FORMAT_RGBA_8888: |
| case GGL_PIXEL_FORMAT_RGB_565: |
| break; |
| case GGL_PIXEL_FORMAT_RGBX_8888: |
| default: |
| ALOGD("pf2: SetBuffer 0x%.04X format=0x%.02X \n", type, surface ? surface->format : 0); |
| assert(0); |
| } |
| } else { |
| memset(&ctx->frameSurface, 0, sizeof(ctx->frameSurface)); |
| changed = true; |
| } |
| ctx->state.bufferState.colorFormat = ctx->frameSurface.format; |
| } else if (GL_DEPTH_BUFFER_BIT == type) { |
| if (surface) { |
| ctx->depthSurface = *surface; |
| changed |= ctx->depthSurface.format ^ surface->format; |
| assert(GGL_PIXEL_FORMAT_Z_32 == ctx->depthSurface.format); |
| } else { |
| memset(&ctx->depthSurface, 0, sizeof(ctx->depthSurface)); |
| changed = true; |
| } |
| ctx->state.bufferState.depthFormat = ctx->depthSurface.format; |
| } else if (GL_STENCIL_BUFFER_BIT == type) { |
| if (surface) { |
| ctx->stencilSurface = *surface; |
| changed |= ctx->stencilSurface.format ^ surface->format; |
| assert(GGL_PIXEL_FORMAT_S_8 == ctx->stencilSurface.format); |
| } else { |
| memset(&ctx->stencilSurface, 0, sizeof(ctx->stencilSurface)); |
| changed = true; |
| } |
| ctx->state.bufferState.stencilFormat = ctx->stencilSurface.format; |
| } else |
| gglError(GL_INVALID_ENUM); |
| if (changed) { |
| SetShaderVerifyFunctions(iface); |
| } |
| } |
| |
| void InitializeBufferFunctions(GGLInterface * iface) |
| { |
| iface->DepthFunc = DepthFunc; |
| iface->StencilFuncSeparate = StencilFuncSeparate; |
| iface->StencilOpSeparate = StencilOpSeparate; |
| iface->StencilSelect = StencilSelect; |
| iface->ClearStencil = ClearStencil; |
| iface->ClearColor = ClearColor; |
| iface->ClearDepthf = ClearDepthf; |
| iface->Clear = Clear; |
| iface->SetBuffer = SetBuffer; |
| } |