/** ** ** 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 <stdlib.h> #include <math.h> #include <string.h> #include <stdio.h> #include "pixelflinger2.h" #include "src/mesa/main/mtypes.h" #include "src/mesa/program/prog_parameter.h" #include "src/mesa/program/prog_uniform.h" #include "src/glsl/glsl_types.h" //#undef ALOGD //#define ALOGD(...) static inline void LerpVector4(const Vector4 * a, const Vector4 * b, const VectorComp_t x, Vector4 * d) __attribute__((always_inline)); static inline void LerpVector4(const Vector4 * a, const Vector4 * b, const VectorComp_t x, Vector4 * d) { assert(a != d && b != d); //d = (b - a) * x + a; (*d) = (*b); (*d) -= (*a); (*d) *= x; (*d) += (*a); } static inline void InterpolateVertex(const VertexOutput * a, const VertexOutput * b, const VectorComp_t x, VertexOutput * v, const unsigned varyingCount) { LerpVector4(&a->position, &b->position, x, &v->position); for (unsigned i = 0; i < varyingCount; i++) LerpVector4(a->varyings + i, b->varyings + i, x, v->varyings + i); LerpVector4(&a->frontFacingPointCoord, &b->frontFacingPointCoord, x, &v->frontFacingPointCoord); // gl_PointCoord v->frontFacingPointCoord.y = a->frontFacingPointCoord.y; // gl_FrontFacing not interpolated } void GGLProcessVertex(const gl_shader_program * program, const VertexInput * input, VertexOutput * output, const float (*constants)[4]) { ShaderFunction_t function = (ShaderFunction_t)program->_LinkedShaders[MESA_SHADER_VERTEX]->function; function(input, output, constants); } static void ProcessVertex(const GGLInterface * iface, const VertexInput * input, VertexOutput * output) { GGL_GET_CONST_CONTEXT(ctx, iface); //#if !USE_LLVM_TEXTURE_SAMPLER // extern const GGLContext * textureGGLContext; // textureGGLContext = ctx; //#endif // // memcpy(ctx->glCtx->CurrentProgram->ValuesVertexInput, input, sizeof(*input)); // ctx->glCtx->CurrentProgram->_LinkedShaders[MESA_SHADER_VERTEX]->function(); // memcpy(output, ctx->glCtx->CurrentProgram->ValuesVertexOutput, sizeof(*output)); GGLProcessVertex(ctx->CurrentProgram, input, output, ctx->CurrentProgram->ValuesUniform); // const Vector4 * constants = (Vector4 *) // ctx->glCtx->Shader.CurrentProgram->VertexProgram->Parameters->ParameterValues; // ctx->glCtx->Shader.CurrentProgram->GLVMVP->function(input, output, constants); // //#if !USE_LLVM_TEXTURE_SAMPLER // textureGGLContext = NULL; //#endif } #if USE_DUAL_THREAD static void * RasterTrapezoidWorker(void * threadArgs) { GGLContext::Worker * args = (GGLContext::Worker *)threadArgs; VertexOutput clip0, clip1, * left, * right; pthread_mutex_lock(&args->finishLock); pthread_mutex_lock(&args->assignLock); pthread_cond_signal(&args->finishCond); pthread_mutex_unlock(&args->finishLock); while (true) { pthread_cond_wait(&args->assignCond, &args->assignLock); if (args->quit) { pthread_mutex_unlock(&args->assignLock); break; } else assert(args->assignedWork); for (unsigned y = args->startY; y <= args->endY; y += 2) { do { if (args->bV.position.x < 0) { if (args->cV.position.x < 0) break; InterpolateVertex(&args->bV, &args->cV, -args->bV.position.x / (args->cV.position.x - args->bV.position.x), &clip0, args->varyingCount); left = &clip0; } else left = &args->bV; if ((int)args->cV.position.x >= (int)args->width) { if (args->bV.position.x >= (int)args->width) break; InterpolateVertex(&args->bV, &args->cV, (args->width - 1 - args->bV.position.x) / (args->cV.position.x - args->bV.position.x), &clip1, args->varyingCount); right = &clip1; } else right = &args->cV; args->iface->ScanLine(args->iface, left, right); } while (false); for (unsigned i = 0; i < args->varyingCount; i++) { args->bV.varyings[i] += args->bDx.varyings[i]; args->cV.varyings[i] += args->cDx.varyings[i]; } args->bV.position += args->bDx.position; args->cV.position += args->cDx.position; args->bV.frontFacingPointCoord += args->bDx.frontFacingPointCoord; args->cV.frontFacingPointCoord += args->cDx.frontFacingPointCoord; } pthread_mutex_lock(&args->finishLock); pthread_cond_signal(&args->finishCond); pthread_mutex_unlock(&args->finishLock); } pthread_exit(NULL); return NULL; } #endif static void RasterTrapezoid(const GGLInterface * iface, const VertexOutput * tl, const VertexOutput * tr, const VertexOutput * bl, const VertexOutput * br) { GGL_GET_CONST_CONTEXT(ctx, iface); assert(tl->position.x <= tr->position.x && bl->position.x <= br->position.x); assert(tl->position.y <= bl->position.y && tr->position.y <= br->position.y); assert(fabs(tl->position.y - tr->position.y) < 1 && fabs(bl->position.y - br->position.y) < 1); const unsigned width = ctx->frameSurface.width, height = ctx->frameSurface.height; const unsigned varyingCount = ctx->CurrentProgram->VaryingSlots; // tlv-trv and blv-brv are parallel and horizontal VertexOutput tlv(*tl), trv(*tr), blv(*bl), brv(*br); VertexOutput tmp; // vertically clip if ((int)tlv.position.y < 0) { InterpolateVertex(&tlv, &blv, (0 - tlv.position.y) / (blv.position.y - tlv.position.y), &tmp, varyingCount); tlv = tmp; } if ((int)trv.position.y < 0) { InterpolateVertex(&trv, &brv, (0 - trv.position.y) / (brv.position.y - trv.position.y), &tmp, varyingCount); trv = tmp; } if ((int)blv.position.y >= (int)height) { InterpolateVertex(&tlv, &blv, (height - 1 - tlv.position.y) / (blv.position.y - tlv.position.y), &tmp, varyingCount); blv = tmp; } if ((int)brv.position.y >= (int)height) { InterpolateVertex(&trv, &brv, (height - 1 - trv.position.y) / (brv.position.y - trv.position.y), &tmp, varyingCount); brv = tmp; } // // horizontally clip // if ((int)tlv.position.x < 0) { // InterpolateVertex(&tlv, &trv, (0 - tlv.position.x) / (trv.position.x - tlv.position.x), // &tmp, varyingCount); // tlv = tmp; // } // if ((int)blv.position.x < 0) { // InterpolateVertex(&blv, &brv, (0 - blv.position.x) / (brv.position.x - blv.position.x), // &tmp, varyingCount); // blv = tmp; // } // if ((int)trv.position.x >= (int)width) { // InterpolateVertex(&tlv, &trv, (width - 1 - tlv.position.x) / (trv.position.x - tlv.position.x), // &tmp, varyingCount); // trv = tmp; // } // if ((int)brv.position.x >= (int)width) { // InterpolateVertex(&blv, &brv, (width - 1 - blv.position.x) / (brv.position.x - blv.position.x), // &tmp, varyingCount); // brv = tmp; // } const unsigned int startY = tlv.position.y; const unsigned int endY = blv.position.y; if (endY < startY) return; const VectorComp_t yDistInv = VectorComp_t_CTR(1.0f / (endY - startY)); // bV and cV are left and right vertices on a horizontal line in quad // bDx and cDx are iterators from tlv to blv, trv to brv for bV and cV VertexOutput bV(tlv), cV(trv); VertexOutput bDx(blv), cDx(brv); for (unsigned i = 0; i < varyingCount; i++) { bDx.varyings[i] -= tlv.varyings[i]; bDx.varyings[i] *= yDistInv; cDx.varyings[i] -= trv.varyings[i]; cDx.varyings[i] *= yDistInv; } bDx.position -= tlv.position; bDx.position *= yDistInv; cDx.position -= trv.position; cDx.position *= yDistInv; bDx.frontFacingPointCoord -= tlv.frontFacingPointCoord; // gl_PointCoord bDx.frontFacingPointCoord *= yDistInv; bDx.frontFacingPointCoord.y = VectorComp_t_Zero; // gl_FrontFacing not interpolated cDx.frontFacingPointCoord -= trv.frontFacingPointCoord; // gl_PointCoord cDx.frontFacingPointCoord *= yDistInv; cDx.frontFacingPointCoord.y = VectorComp_t_Zero; // gl_FrontFacing not interpolated #if USE_DUAL_THREAD GGLContext::Worker & args = ctx->worker; if (!ctx->worker.thread) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); int rc = pthread_create(&ctx->worker.thread, &attr, RasterTrapezoidWorker, &args); assert(!rc); // wait for worker to start pthread_cond_wait(&args.finishCond, &args.finishLock); } args.startY = startY + 1; args.endY = endY; if (args.startY <= args.endY) { pthread_mutex_lock(&args.assignLock); args.bV = bV; args.cV = cV; for (unsigned i = 0; i < varyingCount; i++) { args.bV.varyings[i] += bDx.varyings[i]; bDx.varyings[i] += bDx.varyings[i]; args.cV.varyings[i] += cDx.varyings[i]; cDx.varyings[i] += cDx.varyings[i]; } args.bV.position += bDx.position; bDx.position += bDx.position; args.cV.position += cDx.position; cDx.position += cDx.position; args.bV.frontFacingPointCoord += bDx.frontFacingPointCoord; bDx.frontFacingPointCoord += bDx.frontFacingPointCoord; args.cV.frontFacingPointCoord += cDx.frontFacingPointCoord; cDx.frontFacingPointCoord += cDx.frontFacingPointCoord; args.iface = iface; args.bDx = bDx; args.cDx = cDx; args.varyingCount = varyingCount; args.width = width; args.height = height; args.assignedWork = true; pthread_cond_signal(&args.assignCond); pthread_mutex_unlock(&args.assignLock); } #endif VertexOutput * left, * right; VertexOutput clip0, clip1; for (unsigned y = startY; y <= endY; y += 1 + USE_DUAL_THREAD) { do { if (bV.position.x < 0) { if (cV.position.x < 0) break; InterpolateVertex(&bV, &cV, -bV.position.x / (cV.position.x - bV.position.x), &clip0, varyingCount); left = &clip0; } else left = &bV; if ((int)cV.position.x >= (int)width) { if (bV.position.x >= (int)width) break; InterpolateVertex(&bV, &cV, (width - 1 - bV.position.x) / (cV.position.x - bV.position.x), &clip1, varyingCount); right = &clip1; } else right = &cV; iface->ScanLine(iface, left, right); } while (false); for (unsigned i = 0; i < varyingCount; i++) { bV.varyings[i] += bDx.varyings[i]; cV.varyings[i] += cDx.varyings[i]; } bV.position += bDx.position; cV.position += cDx.position; bV.frontFacingPointCoord += bDx.frontFacingPointCoord; cV.frontFacingPointCoord += cDx.frontFacingPointCoord; } #if USE_DUAL_THREAD if (args.assignedWork) { pthread_cond_wait(&args.finishCond, &args.finishLock); args.assignedWork = false; } #endif } static void RasterTriangle(const GGLInterface * iface, const VertexOutput * v1, const VertexOutput * v2, const VertexOutput * v3) { GGL_GET_CONST_CONTEXT(ctx, iface); const unsigned varyingCount = ctx->CurrentProgram->VaryingSlots; const unsigned height = ctx->frameSurface.height; const VertexOutput * a = v1, * b = v2, * d = v3; //abc is a triangle, bcd is another triangle, they share bc as horizontal edge //c is between a and d, xy is screen coord //first sort 3 vertices by MIN y first if (v2->position.y < v1->position.y) { a = v2; b = v1; } if (v3->position.y < a->position.y) { d = b; b = a; a = v3; } else if (v3->position.y < b->position.y) { d = b; b = v3; } assert(a->position.y <= b->position.y && b->position.y <= d->position.y); VertexOutput cVertex; const VertexOutput* c = &cVertex; const VectorComp_t cLerp = (b->position.y - a->position.y) / MAX2(VectorComp_t_One, (d->position.y - a->position.y)); // create 4th vertex, same y as b to form two triangles/trapezoids sharing horizontal edge InterpolateVertex(a, d, cLerp, &cVertex, varyingCount); if (c->position.x < b->position.x) { const VertexOutput * tmp = c; c = b; b = tmp; } if ((int)a->position.y < (int)height && (int)b->position.y >= 0) RasterTrapezoid(iface, a, a, b, c); //b->position.y += VectorComp_t_One; //c->position.y += VectorComp_t_One; if ((int)b->position.y < (int)height && (int)d->position.y >= 0) RasterTrapezoid(iface, b, c, d, d); } static void DrawTriangle(const GGLInterface * iface, const VertexInput * vin1, const VertexInput * vin2, const VertexInput * vin3) { GGL_GET_CONST_CONTEXT(ctx, iface); VertexOutput vouts[3]; memset(vouts, 0, sizeof(vouts)); VertexOutput * v1 = vouts + 0, * v2 = vouts + 1, * v3 = vouts + 2; // ALOGD("pf2: DrawTriangle"); // if (!strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, // "gl_FragColor = color * texture2D(sampler, outTexCoords).a;")) // return; // for (unsigned i = 0; i < program->NumShaders; i++) // if (program->Shaders[i]->Source) // ALOGD("%s", program->Shaders[i]->Source); // if (!strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, ").a;")) // return; // ALOGD("%s", program->Shaders[MESA_SHADER_VERTEX]->Source); // ALOGD("%s", program->Shaders[MESA_SHADER_FRAGMENT]->Source); // for (unsigned i = 0; i < program->Attributes->NumParameters; i++) { // const gl_program_parameter & attribute = program->Attributes->Parameters[i]; // ALOGD("attribute '%s': location=%d slots=%d \n", attribute.Name, attribute.Location, attribute.Slots); // } // for (unsigned i = 0; i < program->Varying->NumParameters; i++) { // const gl_program_parameter & varying = program->Varying->Parameters[i]; // ALOGD("varying '%s': vs_location=%d fs_location=%d \n", varying.Name, varying.BindLocation, varying.Location); // } // for (unsigned i = 0; i < program->Uniforms->NumUniforms; i++) { // const gl_uniform & uniform = program->Uniforms->Uniforms[i]; // ALOGD("uniform '%s': location=%d type=%s \n", uniform.Name, uniform.Pos, uniform.Type->name); // } // __attribute__ ((aligned (16))) // static const float matrix[16] = { // 1,0,0,0, // 0,1,0,0, // 0,0,1,0, // 0,0,0,1 // }; // // iface->ShaderUniformMatrix((gl_shader_program *)program, 4, 4, 0, 1, GL_FALSE, matrix); iface->ProcessVertex(iface, vin1, v1); iface->ProcessVertex(iface, vin2, v2); iface->ProcessVertex(iface, vin3, v3); // __attribute__ ((aligned (16))) // static const float matrix[16] = { // 2,0,0,0, // 0,-2,0,0, // 0,0,-1,0, // -1,1,0,1 // }; // float * matrix = program->ValuesUniform[0]; // for (unsigned i = 0; i < 4; i++) // ALOGD("pf2: DrawTriangle %.2f \t %.2f \t %.2f \t %.2f \n", matrix[i * 4 + 0], // matrix[i * 4 + 1], matrix[i * 4 + 2], matrix[i * 4 + 3]); //// ALOGD("color %.02f %.02f %.02f %.02f", program->ValuesUniform[4][0], program->ValuesUniform[4][1], //// program->ValuesUniform[4][2], program->ValuesUniform[4][3]); // ALOGD("vin1 position %.02f %.02f %.02f %.02f", vin1->attributes[1].x, vin1->attributes[1].y, // vin1->attributes[1].z, vin1->attributes[1].w); // ALOGD("vin2 position %.02f %.02f %.02f %.02f", vin2->attributes[1].x, vin2->attributes[1].y, // vin2->attributes[1].z, vin2->attributes[1].w); // ALOGD("vin3 position %.02f %.02f %.02f %.02f", vin3->attributes[1].x, vin3->attributes[1].y, // vin3->attributes[1].z, vin3->attributes[1].w); // GGLProcessVertex(program, vin1, v1, (const float (*)[4])matrix); // GGLProcessVertex(program, vin2, v2, (const float (*)[4])matrix); // GGLProcessVertex(program, vin3, v3, (const float (*)[4])matrix); // ALOGD("pf2: DrawTriangle processed %.02f %.02f %.2f %.2f \t %.02f %.02f %.2f %.2f \t %.02f %.02f %.2f %.2f", // v1->position.x, v1->position.y, v1->position.z, v1->position.w, // v2->position.x, v2->position.y, v2->position.z, v2->position.w, // v3->position.x, v3->position.y, v3->position.z, v3->position.w); v1->position /= v1->position.w; v2->position /= v2->position.w; v3->position /= v3->position.w; // ALOGD("pf2: DrawTriangle divided %.02f,%.02f \t %.02f,%.02f \t %.02f,%.02f", v1->position.x, v1->position.y, // v2->position.x, v2->position.y, v3->position.x, v3->position.y); iface->ViewportTransform(iface, &v1->position); iface->ViewportTransform(iface, &v2->position); iface->ViewportTransform(iface, &v3->position); // if (strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, // "gl_FragColor = color * texture2D(sampler, outTexCoords).a;")) { //// ALOGD("%s", program->Shaders[MESA_SHADER_FRAGMENT]->Source); // v1->position = vin1->attributes[0]; // v2->position = vin2->attributes[0]; // v3->position = vin3->attributes[0]; // // v1->varyings[0] = vin1->attributes[1]; // v2->varyings[0] = vin2->attributes[1]; // v3->varyings[0] = vin3->attributes[1]; // } // ALOGD("pf2: DrawTriangle transformed %.0f,%.0f \t %.0f,%.0f \t %.0f,%.0f", v1->position.x, v1->position.y, // v2->position.x, v2->position.y, v3->position.x, v3->position.y); // ALOGD("pf2: DrawTriangle varying %.02f %.02f %.2f %.2f \t %.02f %.02f %.2f %.2f \t %.02f %.02f %.2f %.2f", // v1->varyings[0].x, v1->varyings[0].y, v1->varyings[0].z, v1->varyings[0].w, // v2->varyings[0].x, v2->varyings[0].y, v2->varyings[0].z, v2->varyings[0].w, // v3->varyings[0].x, v3->varyings[0].y, v3->varyings[0].z, v3->varyings[0].w); VectorComp_t area; area = v1->position.x * v2->position.y - v2->position.x * v1->position.y; area += v2->position.x * v3->position.y - v3->position.x * v2->position.y; area += v3->position.x * v1->position.y - v1->position.x * v3->position.y; area *= 0.5f; if (GL_CCW == ctx->cullState.frontFace + GL_CW) (unsigned &)area ^= 0x80000000; if (false && ctx->cullState.enable) { // TODO: turn off for now switch (ctx->cullState.cullFace + GL_FRONT) { case GL_FRONT: if (!((unsigned &)area & 0x80000000)) // +ve, front facing return; break; case GL_BACK: if ((unsigned &)area & 0x80000000) // -ve, back facing return; break; case GL_FRONT_AND_BACK: return; default: assert(0); } } v1->frontFacingPointCoord.y = v2->frontFacingPointCoord.y = v3->frontFacingPointCoord.y = !((unsigned &)area & 0x80000000) ? VectorComp_t_One : VectorComp_t_Zero; iface->StencilSelect(iface, ((unsigned &)area & 0x80000000) ? GL_BACK : GL_FRONT); // if (0) // { // GGLContext * ctx =(GGLContext *)iface; // for (unsigned sampler = 0; sampler < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; sampler++) // { // if (!((1 << sampler) & ctx->glCtx->Shader.CurrentProgram->FragmentProgram->SamplersUsed)) // continue; // const GGLTexture * texture = ctx->textureState.textures + sampler; // int level = texture->width * texture->height / (area * 2) - 4; // assert(texture->levels); // ctx->textureState.textureData[sampler] = texture->levels[0]; // ctx->textureState.textureDimensions[sampler * 2] = texture->width; // ctx->textureState.textureDimensions[sampler * 2 + 1] = texture->height; // for (unsigned i = 1; i < texture->levelCount && i <= level; i++) // { // ctx->textureState.textureData[sampler] = texture->levels[i]; // ctx->textureState.textureDimensions[sampler * 2] += 1; // ctx->textureState.textureDimensions[sampler * 2] /= 2; // ctx->textureState.textureDimensions[sampler * 2 + 1] += 1; // ctx->textureState.textureDimensions[sampler * 2 + 1] /= 2; // } // } // } // TODO DXL view frustum clipping iface->RasterTriangle(iface, v1, v2, v3); // ALOGD("pf2: DrawTriangle end"); } static void PickRaster(GGLInterface * iface) { iface->ProcessVertex = ProcessVertex; iface->DrawTriangle = DrawTriangle; iface->RasterTriangle = RasterTriangle; iface->RasterTrapezoid = RasterTrapezoid; } static void ViewportTransform(const GGLInterface * iface, Vector4 * v) { GGL_GET_CONST_CONTEXT(ctx, iface); v->x = v->x * ctx->viewport.w + ctx->viewport.x; v->y *= -1; v->y = v->y * ctx->viewport.h + ctx->viewport.y; v->z = v->z * ctx->viewport.f + ctx->viewport.n; } void InitializeRasterFunctions(GGLInterface * iface) { GGL_GET_CONTEXT(ctx, iface); ctx->PickRaster = PickRaster; iface->ViewportTransform = ViewportTransform; }