blob: fe457402926feb06785939c729e9f8f44aa41936 [file] [log] [blame]
/**
**
** 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;
}