| /** |
| ** |
| ** Copyright 2011, 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 "src/pixelflinger2/llvm_helper.h" |
| #include "src/mesa/main/mtypes.h" |
| |
| #include <llvm/IR/Module.h> |
| |
| //#undef ALOGD |
| //#define ALOGD(...) |
| |
| using namespace llvm; |
| |
| static void StencilOp(IRBuilder<> &builder, const unsigned char op, |
| Value * sPtr, Value * sRef) |
| { |
| CondBranch condBranch(builder); |
| Value * s = builder.CreateLoad(sPtr, "stenciOpS"); |
| switch (op) { |
| case 0 : // GL_ZERO |
| builder.CreateStore(builder.getInt8(0), sPtr); |
| break; |
| case 1 : // GL_KEEP |
| builder.CreateStore(s, sPtr); |
| break; |
| case 2 : // GL_REPLACE |
| builder.CreateStore(sRef, sPtr); |
| break; |
| case 3 : // GL_INCR |
| condBranch.ifCond(builder.CreateICmpEQ(s, builder.getInt8(255))); |
| builder.CreateStore(s, sPtr); |
| condBranch.elseop(); |
| builder.CreateStore(builder.CreateAdd(s, builder.getInt8(1)), sPtr); |
| condBranch.endif(); |
| break; |
| case 4 : // GL_DECR |
| condBranch.ifCond(builder.CreateICmpEQ(s, builder.getInt8(0))); |
| builder.CreateStore(s, sPtr); |
| condBranch.elseop(); |
| builder.CreateStore(builder.CreateSub(s, builder.getInt8(1)), sPtr); |
| condBranch.endif(); |
| break; |
| case 5 : // GL_INVERT |
| builder.CreateStore(builder.CreateNot(s), sPtr); |
| break; |
| case 6 : // GL_INCR_WRAP |
| builder.CreateStore(builder.CreateAdd(s, builder.getInt8(1)), sPtr); |
| break; |
| case 7 : // GL_DECR_WRAP |
| builder.CreateStore(builder.CreateSub(s, builder.getInt8(1)), sPtr); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| } |
| |
| static Value * StencilOp(IRBuilder<> & builder, Value * face, |
| const unsigned char frontOp, const unsigned char backOp, |
| Value * sPtr, Value * sRef) |
| { |
| CondBranch condBranch(builder); |
| if (frontOp != backOp) |
| condBranch.ifCond(builder.CreateICmpEQ(face, builder.getInt8(0))); |
| |
| StencilOp(builder, frontOp, sPtr, sRef); |
| |
| if (frontOp != backOp) { |
| condBranch.elseop(); |
| StencilOp(builder, backOp, sPtr, sRef); |
| condBranch.endif(); |
| } |
| return builder.CreateLoad(sPtr); |
| } |
| |
| static void StencilFunc(IRBuilder<> & builder, const unsigned char func, |
| Value * s, Value * sRef, Value * sCmpPtr) |
| { |
| switch (func) { |
| case GL_NEVER & 0x7: |
| builder.CreateStore(builder.getFalse(), sCmpPtr); |
| break; |
| case GL_LESS & 0x7: |
| builder.CreateStore(builder.CreateICmpULT(sRef, s), sCmpPtr); |
| break; |
| case GL_EQUAL & 0x7: |
| builder.CreateStore(builder.CreateICmpEQ(sRef, s), sCmpPtr); |
| break; |
| case GL_LEQUAL & 0x7: |
| builder.CreateStore(builder.CreateICmpULE(sRef, s), sCmpPtr); |
| break; |
| case GL_GREATER & 0x7: |
| builder.CreateStore(builder.CreateICmpUGT(sRef, s), sCmpPtr); |
| break; |
| case GL_NOTEQUAL & 0x7: |
| builder.CreateStore(builder.CreateICmpNE(sRef, s), sCmpPtr); |
| break; |
| case GL_GEQUAL & 0x7: |
| builder.CreateStore(builder.CreateICmpUGE(sRef, s), sCmpPtr); |
| break; |
| case GL_ALWAYS & 0x7: |
| builder.CreateStore(builder.getTrue(), sCmpPtr); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| } |
| |
| static Value * BlendFactor(const unsigned mode, Value * src, Value * dst, |
| Value * constant, Value * one, Value * zero, |
| Value * srcA, Value * dstA, Value * constantA, |
| Value * sOne, const bool isVector, IRBuilder<> & builder) |
| { |
| Value * factor = NULL; |
| switch (mode) { |
| case GGLBlendState::GGL_ZERO: |
| factor = zero; |
| break; |
| case GGLBlendState::GGL_ONE: |
| factor = one; |
| break; |
| case GGLBlendState::GGL_SRC_COLOR: |
| factor = src; |
| break; |
| case GGLBlendState::GGL_ONE_MINUS_SRC_COLOR: |
| factor = builder.CreateSub(one, src); |
| break; |
| case GGLBlendState::GGL_DST_COLOR: |
| factor = dst; |
| break; |
| case GGLBlendState::GGL_ONE_MINUS_DST_COLOR: |
| factor = builder.CreateSub(one, dst); |
| break; |
| case GGLBlendState::GGL_SRC_ALPHA: |
| factor = srcA; |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, factor); |
| break; |
| case GGLBlendState::GGL_ONE_MINUS_SRC_ALPHA: |
| factor = builder.CreateSub(sOne, srcA); |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, factor); |
| break; |
| case GGLBlendState::GGL_DST_ALPHA: |
| factor = dstA; |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, factor); |
| break; |
| case GGLBlendState::GGL_ONE_MINUS_DST_ALPHA: |
| factor = builder.CreateSub(sOne, dstA); |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, factor); |
| break; |
| case GGLBlendState::GGL_SRC_ALPHA_SATURATE: |
| // valid only for source color and alpha |
| factor = minIntScalar(builder, srcA, builder.CreateSub(sOne, dstA)); |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, sOne); |
| else |
| factor = sOne; // when it's used for source alpha, it's just 1 |
| break; |
| case GGLBlendState::GGL_CONSTANT_COLOR: |
| factor = constant; |
| break; |
| case GGLBlendState::GGL_ONE_MINUS_CONSTANT_COLOR: |
| factor = builder.CreateSub(one, constant); |
| break; |
| case GGLBlendState::GGL_CONSTANT_ALPHA: |
| factor = constantA; |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, factor); |
| break; |
| case GGLBlendState::GGL_ONE_MINUS_CONSTANT_ALPHA: |
| factor = builder.CreateSub(sOne, constantA); |
| if (isVector) |
| factor = intVec(builder, factor, factor, factor, factor); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| return factor; |
| } |
| |
| static Value * Saturate(IRBuilder<> & builder, Value * intVector) |
| { |
| intVector = intVecMax(builder, intVector, constIntVec(builder, 0,0,0,0)); |
| return intVecMin(builder, intVector, constIntVec(builder, 255,255,255,255)); |
| } |
| |
| // src is int32x4 [0,255] rgba vector, and combines them into int32 |
| // RGB_565 channel order is weird |
| static Value * IntVectorToScreenColor(IRBuilder<> & builder, const GGLPixelFormat format, Value * src) |
| { |
| if (GGL_PIXEL_FORMAT_RGBA_8888 == format) { |
| src = builder.CreateShl(src, constIntVec(builder, 0, 8, 16, 24)); |
| std::vector<Value *> comps = extractVector(builder, src); |
| comps[0] = builder.CreateOr(comps[0], comps[1]); |
| comps[0] = builder.CreateOr(comps[0], comps[2]); |
| comps[0] = builder.CreateOr(comps[0], comps[3]); |
| return comps[0]; |
| } else if (GGL_PIXEL_FORMAT_RGB_565 == format) { |
| src = builder.CreateAnd(src, constIntVec(builder, 0xf8, 0xfc, 0xf8, 0)); |
| std::vector<Value *> comps = extractVector(builder, src); |
| // channel order is weird |
| for (unsigned i = 0; i < 4; i++) |
| comps[i] = builder.CreateTrunc(comps[i], builder.getInt16Ty()); |
| comps[2] = builder.CreateLShr(comps[2], 3); |
| comps[1] = builder.CreateShl(comps[1], 3); |
| comps[0] = builder.CreateShl(comps[0], 8); |
| |
| comps[0] = builder.CreateOr(comps[0], comps[1]); |
| comps[0] = builder.CreateOr(comps[0], comps[2]); |
| return comps[0]; |
| } else if (GGL_PIXEL_FORMAT_UNKNOWN == format) |
| return builder.getInt32(0); |
| else |
| assert(0); |
| return NULL; |
| } |
| |
| // src is int32 or int16, return is int32x4 [0,255] rgba |
| // RGB_565 channel order is weird |
| static Value * ScreenColorToIntVector(IRBuilder<> & builder, const GGLPixelFormat format, Value * src) |
| { |
| src = builder.CreateZExt(src, builder.getInt32Ty()); |
| Value * dst = intVec(builder, src, src, src, src); |
| if (GGL_PIXEL_FORMAT_RGBA_8888 == format) { |
| dst = builder.CreateLShr(dst, constIntVec(builder, 0, 8, 16, 24)); |
| dst = builder.CreateAnd(dst, constIntVec(builder, 0xff, 0xff, 0xff, 0xff)); |
| } else if (GGL_PIXEL_FORMAT_RGB_565 == format) { |
| // channel order is weird |
| dst = builder.CreateAnd(dst, constIntVec(builder, 0xf800, 0x7e0, 0x1f, 0)); |
| dst = builder.CreateLShr(dst, constIntVec(builder, 8, 3, 0, 0)); |
| dst = builder.CreateShl(dst, constIntVec(builder, 0, 0, 3, 0)); |
| dst = builder.CreateOr(dst, constIntVec(builder, 0, 0, 0, 0xff)); |
| } else if (GGL_PIXEL_FORMAT_UNKNOWN == format) |
| ALOGD("pf2: ScreenColorToIntVector GGL_PIXEL_FORMAT_UNKNOWN"); // not set yet, do nothing |
| else |
| assert(0); |
| return dst; |
| } |
| |
| // src is <4 x float> approx [0,1]; dst is <4 x i32> [0,255] from frame buffer; return is i32 |
| Value * GenerateFSBlend(const GGLState * gglCtx, const GGLPixelFormat format, /*const RegDesc * regDesc,*/ |
| IRBuilder<> & builder, Value * src, Value * dst) |
| { |
| Type * const intType = builder.getInt32Ty(); |
| |
| // TODO cast the outputs pointer type to int for writing to minimize bandwidth |
| if (!gglCtx->blendState.enable) { |
| // if (regDesc->IsInt32Color()) |
| // { |
| // debug_printf("GenerateFixedFS dst is already scalar fixed0 \n"); |
| // src = builder.CreateExtractElement(src, builder.getInt32(0)); |
| // src = builder.CreateBitCast(src, intType); // it's already RGBA int32 |
| // } |
| // else if (regDesc->IsVectorType(Float)) |
| // { |
| src = builder.CreateFMul(src, constFloatVec(builder,255,255,255,255)); |
| src = builder.CreateFPToSI(src, intVecType(builder)); |
| src = Saturate(builder, src); |
| src = IntVectorToScreenColor(builder, format, src); |
| // } |
| // else if (regDesc->IsVectorType(Fixed8)) |
| // { |
| // src = builder.CreateBitCast(src, instr->GetIntVectorType()); |
| // src = Saturate(instr, src); |
| // src = IntVectorToColor(instr, storage, src); |
| // } |
| // else if (regDesc->IsVectorType(Fixed16)) |
| // { |
| // src = builder.CreateBitCast(src, instr->GetIntVectorType()); |
| // src = builder.CreateAShr(src, constIntVec(builder,8,8,8,8)); |
| // src = Saturate(instr, src); |
| // src = IntVectorToColor(instr, storage, src); |
| // } |
| // else |
| // assert(0); |
| return src; |
| } |
| // blending, so convert src to <4 x i32> |
| // if (regDesc->IsInt32Color()) |
| // { |
| // src = builder.CreateExtractElement(src, builder.getInt32(0)); |
| // src = builder.CreateBitCast(src, intType); // it's already RGBA int32 |
| // |
| // Value * channels = Constant::getNullValue(instr->GetIntVectorType()); |
| // channels = builder.CreateInsertElement(channels, src, builder.getInt32(0)); |
| // channels = builder.CreateInsertElement(channels, src, builder.getInt32(1)); |
| // channels = builder.CreateInsertElement(channels, src, builder.getInt32(2)); |
| // channels = builder.CreateInsertElement(channels, src, builder.getInt32(3)); |
| // channels = builder.CreateLShr(channels, constIntVec(builder,0, 8, 16, 24)); |
| // channels = builder.CreateAnd(channels, constIntVec(builder,0xff, 0xff, 0xff, 0xff)); |
| // src = channels; |
| // } |
| // else if (regDesc->IsVectorType(Fixed8)) // it's already int32x4 RGBA |
| // src = builder.CreateBitCast(src, instr->GetIntVectorType()); |
| // else if (regDesc->IsVectorType(Fixed16)) |
| // { |
| // src = builder.CreateBitCast(src, instr->GetIntVectorType()); |
| // // TODO DXL consider shl dst by 8 and ashr by 16 in the end for more precision |
| // src = builder.CreateAShr(src, constIntVec(builder,8,8,8,8)); |
| // } |
| // else if (regDesc->IsVectorType(Float)) |
| // { |
| src = builder.CreateFMul(src, constFloatVec(builder,255,255,255,255)); |
| src = builder.CreateFPToSI(src, intVecType(builder)); |
| // } |
| // else |
| // assert(0); |
| |
| Value * const one = constIntVec(builder,255,255,255,255); |
| Value * const zero = constIntVec(builder,0,0,0,0); |
| Value * const sOne = builder.getInt32(255); |
| Value * const sZero = builder.getInt32(0); |
| |
| #if USE_LLVM_SCANLINE |
| Value * constant = constIntVec(builder,gglCtx->blendState.color[0], |
| gglCtx->blendState.color[1], |
| gglCtx->blendState.color[2], |
| gglCtx->blendState.color[3]); |
| #else |
| Value * constant = NULL; |
| assert(0); |
| #endif |
| |
| Value * srcA = extractVector(builder,src)[3]; |
| Value * dstA = extractVector(builder,dst)[3]; |
| Value * constantA = extractVector(builder,constant)[3]; |
| |
| Value * sf = BlendFactor(gglCtx->blendState.scf, src, dst, |
| constant, one, zero, srcA, dstA, |
| constantA, sOne, true, builder); |
| if (gglCtx->blendState.scf != gglCtx->blendState.saf) { |
| Value * sfA = BlendFactor(gglCtx->blendState.saf, srcA, dstA, |
| constantA, sOne, sZero, srcA, dstA, |
| constantA, sOne, false, builder); |
| sf = builder.CreateInsertElement(sf, sfA, builder.getInt32(3), |
| name("sfAStore")); |
| } |
| |
| Value * df = BlendFactor(gglCtx->blendState.dcf, src, dst, |
| constant, one, zero, srcA, dstA, |
| constantA, sOne, true, builder); |
| if (gglCtx->blendState.dcf != gglCtx->blendState.daf) { |
| Value * dfA = BlendFactor(gglCtx->blendState.daf, srcA, dstA, |
| constantA, sOne, sZero, srcA, dstA, |
| constantA, sOne, false, builder); |
| df = builder.CreateInsertElement(df, dfA, builder.getInt32(3), |
| name("dfAStore")); |
| } |
| |
| // this is factor *= 256 / 255; factors have a chance of constant folding |
| sf = builder.CreateAdd(sf, builder.CreateLShr(sf, constIntVec(builder,7,7,7,7))); |
| df = builder.CreateAdd(df, builder.CreateLShr(df, constIntVec(builder,7,7,7,7))); |
| |
| src = builder.CreateMul(src, sf); |
| dst = builder.CreateMul(dst, df); |
| |
| Value * res = NULL; |
| switch (gglCtx->blendState.ce + GL_FUNC_ADD) { |
| case GL_FUNC_ADD: |
| res = builder.CreateAdd(src, dst); |
| break; |
| case GL_FUNC_SUBTRACT: |
| res = builder.CreateSub(src, dst); |
| break; |
| case GL_FUNC_REVERSE_SUBTRACT: |
| res = builder.CreateSub(dst, src); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| if (gglCtx->blendState.ce != gglCtx->blendState.ae) { |
| srcA = extractVector(builder,src)[3]; |
| dstA = extractVector(builder,dst)[3]; |
| Value * resA = NULL; |
| switch (gglCtx->blendState.ae + GL_FUNC_ADD) { |
| case GL_FUNC_ADD: |
| resA = builder.CreateAdd(srcA, dstA); |
| break; |
| case GL_FUNC_SUBTRACT: |
| resA = builder.CreateSub(srcA, dstA); |
| break; |
| case GL_FUNC_REVERSE_SUBTRACT: |
| resA = builder.CreateSub(dstA, srcA); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| res = builder.CreateInsertElement(res, resA, builder.getInt32(3), |
| name("resAStore")); |
| } |
| |
| res = builder.CreateAShr(res, constIntVec(builder,8,8,8,8)); |
| res = Saturate(builder, res); |
| res = IntVectorToScreenColor(builder, format, res); |
| return res; |
| } |
| |
| static FunctionType * ScanLineFunctionType(IRBuilder<> & builder) |
| { |
| std::vector<Type*> funcArgs; |
| VectorType * vectorType = floatVecType(builder); |
| PointerType * vectorPtr = PointerType::get(vectorType, 0); |
| Type * intType = builder.getInt32Ty(); |
| PointerType * intPointerType = PointerType::get(intType, 0); |
| PointerType * bytePointerType = PointerType::get(builder.getInt8Ty(), 0); |
| |
| funcArgs.push_back(vectorPtr); // start |
| funcArgs.push_back(vectorPtr); // step |
| funcArgs.push_back(vectorPtr); // constants |
| funcArgs.push_back(intPointerType); // frame |
| funcArgs.push_back(intPointerType); // depth |
| funcArgs.push_back(bytePointerType); // stencil |
| funcArgs.push_back(bytePointerType); // stencil state |
| funcArgs.push_back(intType); // count |
| |
| FunctionType *functionType = FunctionType::get(/*Result=*/builder.getVoidTy(), |
| llvm::ArrayRef<Type*>(funcArgs), |
| /*isVarArg=*/false); |
| |
| return functionType; |
| } |
| |
| // generated scanline function parameters are VertexOutput * start, VertexOutput * step, |
| // unsigned * frame, int * depth, unsigned char * stencil, |
| // GGLActiveStencilState * stencilState, unsigned count |
| void GenerateScanLine(const GGLState * gglCtx, const gl_shader_program * program, Module * mod, |
| const char * shaderName, const char * scanlineName) |
| { |
| IRBuilder<> builder(mod->getContext()); |
| // debug_printf("GenerateScanLine %s \n", scanlineName); |
| |
| Type * intType = builder.getInt32Ty(); |
| PointerType * intPointerType = PointerType::get(intType, 0); |
| Type * byteType = builder.getInt8Ty(); |
| PointerType * bytePointerType = PointerType::get(byteType, 0); |
| |
| Function * func = mod->getFunction(scanlineName); |
| if (func) |
| return; |
| |
| func = llvm::cast<Function>(mod->getOrInsertFunction(scanlineName, |
| ScanLineFunctionType(builder))); |
| |
| BasicBlock *label_entry = BasicBlock::Create(builder.getContext(), "entry", func, 0); |
| builder.SetInsertPoint(label_entry); |
| CondBranch condBranch(builder); |
| |
| Function::arg_iterator args = func->arg_begin(); |
| Value * start = args++; |
| start->setName("start"); |
| Value * step = args++; |
| step->setName("step"); |
| Value * constants = args++; |
| constants->setName("constants"); |
| |
| // need alloc to be able to assign to it by using store |
| Value * framePtr = builder.CreateAlloca(intPointerType); |
| builder.CreateStore(args++, framePtr); |
| Value * depthPtr = builder.CreateAlloca(intPointerType); |
| builder.CreateStore(args++, depthPtr); |
| Value * stencilPtr = builder.CreateAlloca(bytePointerType); |
| builder.CreateStore(args++, stencilPtr); |
| Value * stencilState = args++; |
| stencilState->setName("stencilState"); |
| Value * countPtr = builder.CreateAlloca(intType); |
| builder.CreateStore(args++, countPtr); |
| |
| Value * sFace = NULL, * sRef = NULL, *sMask = NULL, * sFunc = NULL; |
| if (gglCtx->bufferState.stencilTest) { |
| sFace = builder.CreateLoad(builder.CreateConstInBoundsGEP1_32(stencilState, 0), "sFace"); |
| if (gglCtx->frontStencil.ref == gglCtx->backStencil.ref) |
| sRef = builder.getInt8(gglCtx->frontStencil.ref); |
| else |
| sRef = builder.CreateLoad(builder.CreateConstInBoundsGEP1_32(stencilState, 1), "sRef"); |
| if (gglCtx->frontStencil.mask == gglCtx->backStencil.mask) |
| sMask = builder.getInt8(gglCtx->frontStencil.mask); |
| else |
| sMask = builder.CreateLoad(builder.CreateConstInBoundsGEP1_32(stencilState, 2), "sMask"); |
| if (gglCtx->frontStencil.func == gglCtx->backStencil.func) |
| sFunc = builder.getInt8(gglCtx->frontStencil.func); |
| else |
| sFunc = builder.CreateLoad(builder.CreateConstInBoundsGEP1_32(stencilState, 3), "sFunc"); |
| } |
| |
| condBranch.beginLoop(); // while (count > 0) |
| |
| assert(framePtr && gglCtx); |
| // get values |
| Value * frame = NULL; |
| if (GGL_PIXEL_FORMAT_RGBA_8888 == gglCtx->bufferState.colorFormat) |
| frame = builder.CreateLoad(framePtr); |
| else if (GGL_PIXEL_FORMAT_RGB_565 == gglCtx->bufferState.colorFormat) { |
| frame = builder.CreateLoad(framePtr); |
| frame = builder.CreateBitCast(frame, PointerType::get(builder.getInt16Ty(), 0)); |
| } else if (GGL_PIXEL_FORMAT_UNKNOWN == gglCtx->bufferState.colorFormat) |
| frame = builder.CreateLoad(framePtr); // color buffer not set yet |
| else |
| assert(0); |
| |
| frame->setName("frame"); |
| Value * depth = NULL, * stencil = NULL; |
| if (gglCtx->bufferState.depthTest) { |
| assert(GGL_PIXEL_FORMAT_Z_32 == gglCtx->bufferState.depthFormat); |
| depth = builder.CreateLoad(depthPtr); |
| depth->setName("depth"); |
| } |
| |
| Value * count = builder.CreateLoad(countPtr); |
| count->setName("count"); |
| |
| Value * cmp = builder.CreateICmpEQ(count, builder.getInt32(0)); |
| condBranch.ifCond(cmp, "if_break_loop"); // if (count == 0) |
| condBranch.brk(); // break; |
| condBranch.endif(); |
| |
| Value * sCmpPtr = NULL, * sCmp = NULL, * sPtr = NULL, * s = NULL; |
| if (gglCtx->bufferState.stencilTest) { |
| stencil = builder.CreateLoad(stencilPtr); |
| stencil->setName("stencil"); |
| |
| // temporaries to load/store value |
| sCmpPtr = builder.CreateAlloca(builder.getInt1Ty()); |
| sCmpPtr->setName("sCmpPtr"); |
| sPtr = builder.CreateAlloca(byteType); |
| sPtr->setName("sPtr"); |
| |
| s = builder.CreateLoad(stencil); |
| s = builder.CreateAnd(s, sMask); |
| builder.CreateStore(s, sPtr); |
| |
| if (gglCtx->frontStencil.func != gglCtx->backStencil.func) |
| condBranch.ifCond(builder.CreateICmpEQ(sFace, builder.getInt8(0))); |
| |
| StencilFunc(builder, gglCtx->frontStencil.func, s, sRef, sCmpPtr); |
| |
| if (gglCtx->frontStencil.func != gglCtx->backStencil.func) { |
| condBranch.elseop(); |
| StencilFunc(builder, gglCtx->backStencil.func, s, sRef, sCmpPtr); |
| condBranch.endif(); |
| } |
| |
| sCmp = builder.CreateLoad(sCmpPtr); |
| } else |
| sCmp = ConstantInt::getTrue(mod->getContext()); |
| sCmp->setName("sCmp"); |
| |
| Value * depthZ = NULL, * zPtr = NULL, * z = NULL, * zCmp = NULL; |
| if (gglCtx->bufferState.depthTest) { |
| depthZ = builder.CreateLoad(depth, "depthZ"); // z stored in buffer |
| zPtr = builder.CreateAlloca(intType); // temp store for modifying incoming z |
| zPtr->setName("zPtr"); |
| |
| // modified incoming z |
| z = builder.CreateBitCast(start, intPointerType); |
| z = builder.CreateConstInBoundsGEP1_32(z, (GGL_FS_INPUT_OFFSET + |
| GGL_FS_INPUT_FRAGCOORD_INDEX) * 4 + 2); |
| z = builder.CreateLoad(z, "z"); |
| |
| builder.CreateStore(z, zPtr); |
| |
| Value * zNegative = builder.CreateICmpSLT(z, builder.getInt32(0)); |
| condBranch.ifCond(zNegative); |
| // if (0x80000000 & z) z ^= 0x7fffffff since smaller -ve float means bigger -ve int |
| z = builder.CreateXor(z, builder.getInt32(0x7fffffff)); |
| builder.CreateStore(z, zPtr); |
| |
| condBranch.endif(); |
| |
| z = builder.CreateLoad(zPtr, "z"); |
| |
| switch (0x200 | gglCtx->bufferState.depthFunc) { |
| case GL_NEVER: |
| zCmp = ConstantInt::getFalse(mod->getContext()); |
| break; |
| case GL_LESS: |
| zCmp = builder.CreateICmpSLT(z, depthZ); |
| break; |
| case GL_EQUAL: |
| zCmp = builder.CreateICmpEQ(z, depthZ); |
| break; |
| case GL_LEQUAL: |
| zCmp = builder.CreateICmpSLE(z, depthZ); |
| break; |
| case GL_GREATER: |
| zCmp = builder.CreateICmpSGT(z, depthZ); |
| break; |
| case GL_NOTEQUAL: |
| zCmp = builder.CreateICmpNE(z, depthZ); |
| break; |
| case GL_GEQUAL: |
| zCmp = builder.CreateICmpSGE(z, depthZ); |
| break; |
| case GL_ALWAYS: |
| zCmp = ConstantInt::getTrue(mod->getContext()); |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| } else // no depth test means always pass |
| zCmp = ConstantInt::getTrue(mod->getContext()); |
| zCmp->setName("zCmp"); |
| |
| condBranch.ifCond(sCmp, "if_sCmp", "sCmp_fail"); |
| condBranch.ifCond(zCmp, "if_zCmp", "zCmp_fail"); |
| |
| Value * inputs = start; |
| Value * outputs = start; |
| |
| Value * fsOutputs = builder.CreateConstInBoundsGEP1_32(start, |
| offsetof(VertexOutput,fragColor)/sizeof(Vector4)); |
| |
| Function * fsFunction = mod->getFunction(shaderName); |
| assert(fsFunction); |
| CallInst *call = builder.CreateCall3(fsFunction,inputs, outputs, constants); |
| call->setCallingConv(CallingConv::C); |
| call->setTailCall(false); |
| |
| Value * dst = Constant::getNullValue(intVecType(builder)); |
| if (gglCtx->blendState.enable && (0 != gglCtx->blendState.dcf || 0 != gglCtx->blendState.daf)) { |
| Value * frameColor = builder.CreateLoad(frame, "frameColor"); |
| dst = ScreenColorToIntVector(builder, gglCtx->bufferState.colorFormat, frameColor); |
| } |
| |
| Value * src = builder.CreateConstInBoundsGEP1_32(fsOutputs, 0); |
| src = builder.CreateLoad(src); |
| |
| Value * color = GenerateFSBlend(gglCtx, gglCtx->bufferState.colorFormat,/*&prog->outputRegDesc,*/ builder, src, dst); |
| builder.CreateStore(color, frame); |
| // TODO DXL depthmask check |
| if (gglCtx->bufferState.depthTest) { |
| z = builder.CreateBitCast(z, intType); |
| builder.CreateStore(z, depth); // store z |
| } |
| |
| if (gglCtx->bufferState.stencilTest) |
| builder.CreateStore(StencilOp(builder, sFace, gglCtx->frontStencil.dPass, |
| gglCtx->backStencil.dPass, sPtr, sRef), stencil); |
| |
| condBranch.elseop(); // failed z test |
| |
| if (gglCtx->bufferState.stencilTest) |
| builder.CreateStore(StencilOp(builder, sFace, gglCtx->frontStencil.dFail, |
| gglCtx->backStencil.dFail, sPtr, sRef), stencil); |
| condBranch.endif(); |
| condBranch.elseop(); // failed s test |
| |
| if (gglCtx->bufferState.stencilTest) |
| builder.CreateStore(StencilOp(builder, sFace, gglCtx->frontStencil.sFail, |
| gglCtx->backStencil.sFail, sPtr, sRef), stencil); |
| |
| condBranch.endif(); |
| assert(frame); |
| frame = builder.CreateConstInBoundsGEP1_32(frame, 1); // frame++ |
| // frame may have been casted to short* from int*, so cast back |
| frame = builder.CreateBitCast(frame, PointerType::get(builder.getInt32Ty(), 0)); |
| builder.CreateStore(frame, framePtr); |
| if (gglCtx->bufferState.depthTest) { |
| depth = builder.CreateConstInBoundsGEP1_32(depth, 1); // depth++ |
| builder.CreateStore(depth, depthPtr); |
| } |
| if (gglCtx->bufferState.stencilTest) { |
| stencil = builder.CreateConstInBoundsGEP1_32(stencil, 1); // stencil++ |
| builder.CreateStore(stencil, stencilPtr); |
| } |
| Value * vPtr = NULL, * v = NULL, * dx = NULL; |
| if (program->UsesFragCoord) { |
| vPtr = builder.CreateConstInBoundsGEP1_32(start, GGL_FS_INPUT_OFFSET + |
| GGL_FS_INPUT_FRAGCOORD_INDEX); |
| v = builder.CreateLoad(vPtr); |
| dx = builder.CreateConstInBoundsGEP1_32(step, GGL_FS_INPUT_OFFSET + |
| GGL_FS_INPUT_FRAGCOORD_INDEX); |
| dx = builder.CreateLoad(dx); |
| v = builder.CreateFAdd(v, dx); |
| builder.CreateStore(v, vPtr); |
| } else if (gglCtx->bufferState.depthTest) { |
| Type * floatType = builder.getFloatTy(); |
| PointerType * floatPointerType = PointerType::get(floatType, 0); |
| vPtr = builder.CreateBitCast(start, floatPointerType); |
| vPtr = builder.CreateConstInBoundsGEP1_32(vPtr, |
| (GGL_FS_INPUT_OFFSET + GGL_FS_INPUT_FRAGCOORD_INDEX) * 4 + 2); |
| v = builder.CreateLoad(vPtr); |
| dx = builder.CreateBitCast(step, floatPointerType); |
| dx = builder.CreateConstInBoundsGEP1_32(dx, |
| (GGL_FS_INPUT_OFFSET + GGL_FS_INPUT_FRAGCOORD_INDEX) * 4 + 2); |
| dx = builder.CreateLoad(dx); |
| v = builder.CreateFAdd(v, dx); |
| builder.CreateStore(v, vPtr); |
| } |
| |
| if (program->UsesPointCoord) { |
| vPtr = builder.CreateConstInBoundsGEP1_32(start, GGL_FS_INPUT_OFFSET + |
| GGL_FS_INPUT_FRONTFACINGPOINTCOORD_INDEX); |
| v = builder.CreateLoad(vPtr); |
| dx = builder.CreateConstInBoundsGEP1_32(step, GGL_FS_INPUT_OFFSET + |
| GGL_FS_INPUT_FRONTFACINGPOINTCOORD_INDEX); |
| dx = builder.CreateLoad(dx); |
| v = builder.CreateFAdd(v, dx); |
| builder.CreateStore(v, vPtr); |
| } |
| |
| for (unsigned i = 0; i < program->VaryingSlots; ++i) { |
| vPtr = builder.CreateConstInBoundsGEP1_32(start, offsetof(VertexOutput,varyings)/sizeof(Vector4) + i); |
| v = builder.CreateLoad(vPtr); |
| dx = builder.CreateConstInBoundsGEP1_32(step, GGL_FS_INPUT_OFFSET + |
| GGL_FS_INPUT_VARYINGS_INDEX + i); |
| dx = builder.CreateLoad(dx); |
| v = builder.CreateFAdd(v, dx); |
| builder.CreateStore(v, vPtr); |
| } |
| |
| count = builder.CreateSub(count, builder.getInt32(1)); |
| builder.CreateStore(count, countPtr); // count--; |
| |
| condBranch.endLoop(); |
| |
| builder.CreateRetVoid(); |
| } |