blob: e8abd796ba1fe4f826fc0bc2986784b53fac0342 [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 <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;
}