/** ** ** 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/Module.h> //#undef LOGD //#define LOGD(...) 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) LOGD("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(); }