Skip to content

Commit

Permalink
Remove cached light variables to reduce work when parsing DLs.
Browse files Browse the repository at this point in the history
Also removes some duplication between GL and the inactive D3D code.
  • Loading branch information
hrydgard committed Apr 21, 2014
1 parent 1d545f3 commit 16f4622
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 577 deletions.
Empty file added GPU/Common/SoftwareLighting.h
Empty file.
177 changes: 177 additions & 0 deletions GPU/Common/TransformCommon.cpp
@@ -0,0 +1,177 @@

// Copyright (c) 2013- PPSSPP Project.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.

#include <stdio.h>

#include "GPU/GPUState.h"
#include "GPU/Common/TransformCommon.h"

// Check for max first as clamping to max is more common than min when lighting.
inline float clamp(float in, float min, float max) {
return in > max ? max : (in < min ? min : in);
}

Lighter::Lighter(int vertType) {
doShadeMapping_ = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP;
materialEmissive.GetFromRGB(gstate.materialemissive);
materialEmissive.a = 0.0f;
globalAmbient.GetFromRGB(gstate.ambientcolor);
globalAmbient.GetFromA(gstate.ambientalpha);
materialAmbient.GetFromRGB(gstate.materialambient);
materialAmbient.GetFromA(gstate.materialalpha);
materialDiffuse.GetFromRGB(gstate.materialdiffuse);
materialDiffuse.a = 1.0f;
materialSpecular.GetFromRGB(gstate.materialspecular);
materialSpecular.a = 1.0f;
specCoef_ = getFloat24(gstate.materialspecularcoef);
// viewer_ = Vec3f(-gstate.viewMatrix[9], -gstate.viewMatrix[10], -gstate.viewMatrix[11]);
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
materialUpdate_ = hasColor ? (gstate.materialupdate & 7) : 0;

// TODO: Easy SSE
for (int l = 0; l < 12; l++) {
lpos[l] = getFloat24(gstate.lpos[l]);
ldir[l] = getFloat24(gstate.ldir[l]);
latt[l] = getFloat24(gstate.latt[l]);
}
for (int l = 0; l < 4; l++) {
lcutoff[l] = getFloat24(gstate.lcutoff[l]);
lconv[l] = getFloat24(gstate.lconv[l]);
}

for (int l = 0; l < 4; l++) {
for (int t = 0; t < 3; t++) {
u32 data = gstate.lcolor[l * 3 + t] & 0xFFFFFF;
float r = (float)(data & 0xff) * (1.0f / 255.0f);
float g = (float)((data >> 8) & 0xff) * (1.0f / 255.0f);
float b = (float)(data >> 16) * (1.0f / 255.0f);
lcolor[t][l][0] = r;
lcolor[t][l][1] = g;
lcolor[t][l][2] = b;
}
}
}

void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[4], const Vec3f &pos, const Vec3f &norm) {
Color4 in(colorIn);

const Color4 *ambient;
if (materialUpdate_ & 1)
ambient = &in;
else
ambient = &materialAmbient;

const Color4 *diffuse;
if (materialUpdate_ & 2)
diffuse = &in;
else
diffuse = &materialDiffuse;

const Color4 *specular;
if (materialUpdate_ & 4)
specular = &in;
else
specular = &materialSpecular;

Color4 lightSum0 = globalAmbient * *ambient + materialEmissive;
Color4 lightSum1(0, 0, 0, 0);

for (int l = 0; l < 4; l++) {
// can we skip this light?
if (!gstate.isLightChanEnabled(l))
continue;

GELightType type = gstate.getLightType(l);

Vec3f toLight(0, 0, 0);
Vec3f lightDir(0, 0, 0);

if (type == GE_LIGHTTYPE_DIRECTIONAL)
toLight = Vec3f(&lpos[l * 3]); // lightdir is for spotlights
else
toLight = Vec3f(&lpos[l * 3]) - pos;

bool doSpecular = gstate.isUsingSpecularLight(l);
bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(l);

float distanceToLight = toLight.Length();
float dot = 0.0f;
float angle = 0.0f;
float lightScale = 0.0f;

if (distanceToLight > 0.0f) {
toLight /= distanceToLight;
dot = Dot(toLight, norm);
}
// Clamp dot to zero.
if (dot < 0.0f) dot = 0.0f;

if (poweredDiffuse)
dot = powf(dot, specCoef_);

// Attenuation
switch (type) {
case GE_LIGHTTYPE_DIRECTIONAL:
lightScale = 1.0f;
break;
case GE_LIGHTTYPE_POINT:
lightScale = clamp(1.0f / (latt[l * 3] + latt[l * 3 + 1] * distanceToLight + latt[l * 3 + 2] * distanceToLight*distanceToLight), 0.0f, 1.0f);
break;
case GE_LIGHTTYPE_SPOT:
case GE_LIGHTTYPE_UNKNOWN:
lightDir = Vec3f(&ldir[l * 3]);
angle = Dot(toLight.Normalized(), lightDir.Normalized());
if (angle >= lcutoff[l])
lightScale = clamp(1.0f / (latt[l * 3] + latt[l * 3 + 1] * distanceToLight + latt[l * 3 + 2] * distanceToLight*distanceToLight), 0.0f, 1.0f) * powf(angle, lconv[l]);
break;
default:
// ILLEGAL
break;
}

Color4 lightDiff(lcolor[1][l], 0.0f);
Color4 diff = (lightDiff * *diffuse) * dot;

// Real PSP specular
Vec3f toViewer(0, 0, 1);
// Better specular
// Vec3f toViewer = (viewer - pos).Normalized();

if (doSpecular) {
Vec3f halfVec = (toLight + toViewer);
halfVec.Normalize();

dot = Dot(halfVec, norm);
if (dot > 0.0f) {
Color4 lightSpec(lcolor[2][l], 0.0f);
lightSum1 += (lightSpec * *specular * (powf(dot, specCoef_) * lightScale));
}
}

if (gstate.isLightChanEnabled(l)) {
Color4 lightAmbient(lcolor[0][l], 0.0f);
lightSum0 += (lightAmbient * *ambient + diff) * lightScale;
}
}

// 4?
for (int i = 0; i < 4; i++) {
colorOut0[i] = lightSum0[i] > 1.0f ? 1.0f : lightSum0[i];
colorOut1[i] = lightSum1[i] > 1.0f ? 1.0f : lightSum1[i];
}
}
93 changes: 93 additions & 0 deletions GPU/Common/TransformCommon.h
@@ -0,0 +1,93 @@
// Copyright (c) 2014- PPSSPP Project.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.

#pragma once

#include <cstring>
#include "base/basictypes.h"
#include "Common/Log.h"
#include "Common/CommonTypes.h"
#include "Core/Reporting.h"
#include "GPU/ge_constants.h"
#include "GPU/Math3D.h"

struct Color4 {
float r, g, b, a;

Color4() : r(0), g(0), b(0), a(0) { }
Color4(float _r, float _g, float _b, float _a = 1.0f)
: r(_r), g(_g), b(_b), a(_a) {
}
Color4(const float in[4]) { r = in[0]; g = in[1]; b = in[2]; a = in[3]; }
Color4(const float in[3], float alpha) { r = in[0]; g = in[1]; b = in[2]; a = alpha; }

const float &operator [](int i) const { return *(&r + i); }

Color4 operator *(float f) const {
return Color4(f*r, f*g, f*b, f*a);
}
Color4 operator *(const Color4 &c) const {
return Color4(r*c.r, g*c.g, b*c.b, a*c.a);
}
Color4 operator +(const Color4 &c) const {
return Color4(r + c.r, g + c.g, b + c.b, a + c.a);
}
void operator +=(const Color4 &c) {
r += c.r;
g += c.g;
b += c.b;
a += c.a;
}
void GetFromRGB(u32 col) {
b = ((col >> 16) & 0xff) * (1.0f / 255.0f);
g = ((col >> 8) & 0xff) * (1.0f / 255.0f);
r = ((col >> 0) & 0xff) * (1.0f / 255.0f);
}
void GetFromA(u32 col) {
a = (col & 0xff) * (1.0f / 255.0f);
}
};

// Convenient way to do precomputation to save the parts of the lighting calculation
// that's common between the many vertices of a draw call.
class Lighter {
public:
Lighter(int vertType);
void Light(float colorOut0[4], float colorOut1[4], const float colorIn[4], const Vec3f &pos, const Vec3f &normal);

private:
Color4 globalAmbient;
Color4 materialEmissive;
Color4 materialAmbient;
Color4 materialDiffuse;
Color4 materialSpecular;
float specCoef_;
// Vec3f viewer_;
bool doShadeMapping_;
int materialUpdate_;

// Converted light parameters
public:
float lpos[12]; // Used by shade UV mapping
private:
float ldir[12];
float latt[12];
float lcutoff[4];
float lconv[4];
float lcolor[3][4][3];
};

105 changes: 31 additions & 74 deletions GPU/Directx9/GPU_DX9.cpp
Expand Up @@ -953,89 +953,46 @@ void DIRECTX9_GPU::ExecuteOp(u32 op, u32 diff) {
case GE_CMD_LIGHTTYPE2:
case GE_CMD_LIGHTTYPE3:
break;

case GE_CMD_LX0:case GE_CMD_LY0:case GE_CMD_LZ0:
case GE_CMD_LX1:case GE_CMD_LY1:case GE_CMD_LZ1:
case GE_CMD_LX2:case GE_CMD_LY2:case GE_CMD_LZ2:
case GE_CMD_LX3:case GE_CMD_LY3:case GE_CMD_LZ3:
{
int n = cmd - GE_CMD_LX0;
int l = n / 3;
int c = n % 3;
gstate_c.lightpos[l][c] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
break;

case GE_CMD_LDX0:case GE_CMD_LDY0:case GE_CMD_LDZ0:
case GE_CMD_LDX1:case GE_CMD_LDY1:case GE_CMD_LDZ1:
case GE_CMD_LDX2:case GE_CMD_LDY2:case GE_CMD_LDZ2:
case GE_CMD_LDX3:case GE_CMD_LDY3:case GE_CMD_LDZ3:
{
int n = cmd - GE_CMD_LDX0;
int l = n / 3;
int c = n % 3;
gstate_c.lightdir[l][c] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
break;

case GE_CMD_LKA0:case GE_CMD_LKB0:case GE_CMD_LKC0:
case GE_CMD_LKA1:case GE_CMD_LKB1:case GE_CMD_LKC1:
case GE_CMD_LKA2:case GE_CMD_LKB2:case GE_CMD_LKC2:
case GE_CMD_LKA3:case GE_CMD_LKB3:case GE_CMD_LKC3:
{
int n = cmd - GE_CMD_LKA0;
int l = n / 3;
int c = n % 3;
gstate_c.lightatt[l][c] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
case GE_CMD_LKS0: // spot coef ("conv")
case GE_CMD_LKO0: // light angle ("cutoff")
case GE_CMD_LAC0:
case GE_CMD_LDC0:
case GE_CMD_LSC0:
shaderManager_->DirtyUniform(DIRTY_LIGHT0);
break;

case GE_CMD_LKS0:
case GE_CMD_LX1:case GE_CMD_LY1:case GE_CMD_LZ1:
case GE_CMD_LDX1:case GE_CMD_LDY1:case GE_CMD_LDZ1:
case GE_CMD_LKA1:case GE_CMD_LKB1:case GE_CMD_LKC1:
case GE_CMD_LKS1:
case GE_CMD_LKS2:
case GE_CMD_LKS3:
{
int l = cmd - GE_CMD_LKS0;
gstate_c.lightspotCoef[l] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
break;

case GE_CMD_LKO0:
case GE_CMD_LKO1:
case GE_CMD_LAC1:
case GE_CMD_LDC1:
case GE_CMD_LSC1:
shaderManager_->DirtyUniform(DIRTY_LIGHT1);
break;
case GE_CMD_LX2:case GE_CMD_LY2:case GE_CMD_LZ2:
case GE_CMD_LDX2:case GE_CMD_LDY2:case GE_CMD_LDZ2:
case GE_CMD_LKA2:case GE_CMD_LKB2:case GE_CMD_LKC2:
case GE_CMD_LKS2:
case GE_CMD_LKO2:
case GE_CMD_LKO3:
{
int l = cmd - GE_CMD_LKO0;
gstate_c.lightangle[l] = getFloat24(data);
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
case GE_CMD_LAC2:
case GE_CMD_LDC2:
case GE_CMD_LSC2:
shaderManager_->DirtyUniform(DIRTY_LIGHT2);
break;

case GE_CMD_LAC0:case GE_CMD_LAC1:case GE_CMD_LAC2:case GE_CMD_LAC3:
case GE_CMD_LDC0:case GE_CMD_LDC1:case GE_CMD_LDC2:case GE_CMD_LDC3:
case GE_CMD_LSC0:case GE_CMD_LSC1:case GE_CMD_LSC2:case GE_CMD_LSC3:
{
float r = (float)(data & 0xff)/255.0f;
float g = (float)((data>>8) & 0xff)/255.0f;
float b = (float)(data>>16)/255.0f;

int l = (cmd - GE_CMD_LAC0) / 3;
int t = (cmd - GE_CMD_LAC0) % 3;
gstate_c.lightColor[t][l][0] = r;
gstate_c.lightColor[t][l][1] = g;
gstate_c.lightColor[t][l][2] = b;
if (diff)
shaderManager_->DirtyUniform(DIRTY_LIGHT0 << l);
}
case GE_CMD_LX3:case GE_CMD_LY3:case GE_CMD_LZ3:
case GE_CMD_LDX3:case GE_CMD_LDY3:case GE_CMD_LDZ3:
case GE_CMD_LKA3:case GE_CMD_LKB3:case GE_CMD_LKC3:
case GE_CMD_LKS3:
case GE_CMD_LKO3:
case GE_CMD_LAC3:
case GE_CMD_LDC3:
case GE_CMD_LSC3:
shaderManager_->DirtyUniform(DIRTY_LIGHT3);
break;

case GE_CMD_VIEWPORTX1:
Expand Down

0 comments on commit 16f4622

Please sign in to comment.