Move most GL code out of GLES/SoftwareTransform.cpp

This commit is contained in:
Henrik Rydgard 2014-09-13 13:03:37 +02:00
parent b4690b23d6
commit ca3ed34b44
4 changed files with 107 additions and 80 deletions

View File

@ -149,7 +149,8 @@ public:
private: private:
void DecodeVerts(); void DecodeVerts();
void DecodeVertsStep(); void DecodeVertsStep();
void DoFlush(); void
DoFlush();
void SoftwareTransformAndDraw(int prim, u8 *decoded, int vertexCount, u32 vertexType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex); void SoftwareTransformAndDraw(int prim, u8 *decoded, int vertexCount, u32 vertexType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex);
void ApplyDrawState(int prim); void ApplyDrawState(int prim);
void ApplyDrawStateLate(); void ApplyDrawStateLate();

View File

@ -15,7 +15,6 @@
// Official git repository and contact information can be found at // Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "gfx_es2/gl_state.h"
#include "math/math_util.h" #include "math/math_util.h"
#include "Core/Config.h" #include "Core/Config.h"
@ -23,8 +22,7 @@
#include "GPU/Math3D.h" #include "GPU/Math3D.h"
#include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/VertexDecoderCommon.h"
#include "GPU/Common/TransformCommon.h" #include "GPU/Common/TransformCommon.h"
#include "GPU/GLES/Framebuffer.h" #include "GPU/Common/FramebufferCommon.h"
#include "GPU/GLES/ShaderManager.h"
#include "GPU/GLES/TextureCache.h" #include "GPU/GLES/TextureCache.h"
#include "GPU/GLES/TransformPipeline.h" #include "GPU/GLES/TransformPipeline.h"
@ -34,7 +32,7 @@
// There's code here that simply expands transformed RECTANGLES into plain triangles. // There's code here that simply expands transformed RECTANGLES into plain triangles.
// We're gonna have to keep software transforming RECTANGLES, unless we use a geom shader which we can't on OpenGL ES 2.0. // We're gonna have to keep software transforming RECTANGLES, unless we use a geom shader which we can't on OpenGL ES 2.0 or DX9.
// Usually, though, these primitives don't use lighting etc so it's no biggie performance wise, but it would be nice to get rid of // Usually, though, these primitives don't use lighting etc so it's no biggie performance wise, but it would be nice to get rid of
// this code. // this code.
@ -45,8 +43,6 @@
// GL_TRIANGLES. Still need to sw transform to compute the extra two corners though. // GL_TRIANGLES. Still need to sw transform to compute the extra two corners though.
// //
extern const GLuint glprim[8];
// The verts are in the order: BR BL TL TR // The verts are in the order: BR BL TL TR
static void SwapUVs(TransformedVertex &a, TransformedVertex &b) { static void SwapUVs(TransformedVertex &a, TransformedVertex &b) {
float tempu = a.u; float tempu = a.u;
@ -124,9 +120,9 @@ bool TransformDrawEngine::IsReallyAClear(int numVerts) const {
} }
void TransformDrawEngine::SoftwareTransformAndDraw( void TransformDrawEngine::SoftwareTransform(
int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex) { int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertType, void *inds, int indexType,
const DecVtxFormat &decVtxFormat, int maxIndex, FramebufferManagerCommon *fbman, TransformedVertex *&drawBuffer, int &numTrans, bool &drawIndexed, SoftwareTransformResult *result) {
bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0; bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0;
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled(); bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
@ -387,48 +383,15 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
} }
// Here's the best opportunity to try to detect rectangles used to clear the screen, and // Here's the best opportunity to try to detect rectangles used to clear the screen, and
// replace them with real OpenGL clears. This can provide a speedup on certain mobile chips. // replace them with real clears. This can provide a speedup on certain mobile chips.
// //
// An alternative option is to simply ditch all the verts except the first and last to create a single // An alternative option is to simply ditch all the verts except the first and last to create a single
// rectangle out of many. Quite a small optimization though. // rectangle out of many. Quite a small optimization though.
// Experiment: Disable on PowerVR (see issue #6290) // Experiment: Disable on PowerVR (see issue #6290)
if (maxIndex > 1 && gstate.isModeClear() && prim == GE_PRIM_RECTANGLES && IsReallyAClear(maxIndex) && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { if (maxIndex > 1 && gstate.isModeClear() && prim == GE_PRIM_RECTANGLES && IsReallyAClear(maxIndex) && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) {
u32 clearColor = transformed[0].color0_32; result->color = transformed[0].color0_32;
float clearDepth = transformed[0].z; result->depth = transformed[0].z;
const float col[4] = { result->action = SW_CLEAR;
((clearColor & 0xFF)) / 255.0f,
((clearColor & 0xFF00) >> 8) / 255.0f,
((clearColor & 0xFF0000) >> 16) / 255.0f,
((clearColor & 0xFF000000) >> 24) / 255.0f,
};
bool colorMask = gstate.isClearModeColorMask();
bool alphaMask = gstate.isClearModeAlphaMask();
bool depthMask = gstate.isClearModeDepthMask();
if (depthMask) {
framebufferManager_->SetDepthUpdated();
}
// Note that scissor may still apply while clearing. Turn off other tests for the clear.
glstate.stencilTest.disable();
glstate.stencilMask.set(0xFF);
glstate.depthTest.disable();
GLbitfield target = 0;
if (colorMask || alphaMask) target |= GL_COLOR_BUFFER_BIT;
if (alphaMask) target |= GL_STENCIL_BUFFER_BIT;
if (depthMask) target |= GL_DEPTH_BUFFER_BIT;
glClearColor(col[0], col[1], col[2], col[3]);
#ifdef USING_GLES2
glClearDepthf(clearDepth);
#else
glClearDepth(clearDepth);
#endif
// Stencil takes alpha.
glClearStencil(clearColor >> 24);
glClear(target);
framebufferManager_->SetColorUpdated();
return; return;
} }
@ -442,8 +405,8 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
if (tlOutside || brOutside) { if (tlOutside || brOutside) {
// Okay, so we're texturing from outside the framebuffer, but inside the texture height. // Okay, so we're texturing from outside the framebuffer, but inside the texture height.
// Breath of Fire 3 does this to access a render surface at an offset. // Breath of Fire 3 does this to access a render surface at an offset.
const u32 bpp = framebufferManager_->GetTargetFormat() == GE_FORMAT_8888 ? 4 : 2; const u32 bpp = fbman->GetTargetFormat() == GE_FORMAT_8888 ? 4 : 2;
const u32 fb_size = bpp * framebufferManager_->GetTargetStride() * gstate_c.curTextureHeight; const u32 fb_size = bpp * fbman->GetTargetStride() * gstate_c.curTextureHeight;
const u32 prevH = gstate_c.curTextureHeight; const u32 prevH = gstate_c.curTextureHeight;
const u32 prevYOffset = gstate_c.curTextureYOffset; const u32 prevYOffset = gstate_c.curTextureYOffset;
if (textureCache_->SetOffsetTexture(fb_size)) { if (textureCache_->SetOffsetTexture(fb_size)) {
@ -466,10 +429,9 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
} }
// Step 2: expand rectangles. // Step 2: expand rectangles.
const TransformedVertex *drawBuffer = transformed; drawBuffer = transformed;
int numTrans = 0; numTrans = 0;
drawIndexed = false;
bool drawIndexed = false;
if (prim != GE_PRIM_RECTANGLES) { if (prim != GE_PRIM_RECTANGLES) {
// We can simply draw the unexpanded buffer. // We can simply draw the unexpanded buffer.
@ -534,30 +496,10 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
// We don't know the color until here, so we have to do it now, instead of in StateMapping. // We don't know the color until here, so we have to do it now, instead of in StateMapping.
// Might want to reconsider the order of things later... // Might want to reconsider the order of things later...
if (gstate.isModeClear() && gstate.isClearModeAlphaMask()) { if (gstate.isModeClear() && gstate.isClearModeAlphaMask()) {
glstate.stencilFunc.set(GL_ALWAYS, stencilValue, 255); result->setStencil = true;
result->stencilValue = stencilValue;
} }
} }
// TODO: Add a post-transform cache here for multi-RECTANGLES only. result->action = SW_DRAW_PRIMITIVES;
// Might help for text drawing.
// these spam the gDebugger log.
const int vertexSize = sizeof(transformed[0]);
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
int attrMask = program->attrMask;
if (attrMask & (1 << ATTR_TEXCOORD)) glVertexAttribPointer(ATTR_TEXCOORD, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + offsetof(TransformedVertex, u));
if (attrMask & (1 << ATTR_COLOR0)) glVertexAttribPointer(ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + offsetof(TransformedVertex, color0));
if (attrMask & (1 << ATTR_COLOR1)) glVertexAttribPointer(ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + offsetof(TransformedVertex, color1));
if (drawIndexed) {
#if 1 // USING_GLES2
glDrawElements(glprim[prim], numTrans, GL_UNSIGNED_SHORT, inds);
#else
glDrawRangeElements(glprim[prim], 0, indexGen.MaxIndex(), numTrans, GL_UNSIGNED_SHORT, inds);
#endif
} else {
glDrawArrays(glprim[prim], 0, numTrans);
}
} }

View File

@ -759,10 +759,78 @@ rotateVBO:
if (prim == GE_PRIM_TRIANGLE_STRIP) if (prim == GE_PRIM_TRIANGLE_STRIP)
prim = GE_PRIM_TRIANGLES; prim = GE_PRIM_TRIANGLES;
SoftwareTransformAndDraw( TransformedVertex *drawBuffer = NULL;
int numTrans;
bool drawIndexed = false;
u16 *inds = decIndex;
SoftwareTransformResult result;
memset(&result, 0, sizeof(result));
SoftwareTransform(
prim, decoded, program, indexGen.VertexCount(), prim, decoded, program, indexGen.VertexCount(),
dec_->VertexType(), (void *)decIndex, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(), dec_->VertexType(), (void *)inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
indexGen.MaxIndex()); indexGen.MaxIndex(), framebufferManager_, drawBuffer, numTrans, drawIndexed, &result);
if (result.action == SW_DRAW_PRIMITIVES) {
if (result.setStencil) {
glstate.stencilFunc.set(GL_ALWAYS, result.stencilValue, 255);
}
const int vertexSize = sizeof(transformed[0]);
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
glBindBuffer(GL_ARRAY_BUFFER, 0);
glVertexAttribPointer(ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
int attrMask = program->attrMask;
if (attrMask & (1 << ATTR_TEXCOORD)) glVertexAttribPointer(ATTR_TEXCOORD, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, ((uint8_t*)drawBuffer) + offsetof(TransformedVertex, u));
if (attrMask & (1 << ATTR_COLOR0)) glVertexAttribPointer(ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + offsetof(TransformedVertex, color0));
if (attrMask & (1 << ATTR_COLOR1)) glVertexAttribPointer(ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, ((uint8_t*)drawBuffer) + offsetof(TransformedVertex, color1));
if (drawIndexed) {
#if 1 // USING_GLES2
glDrawElements(glprim[prim], numTrans, GL_UNSIGNED_SHORT, inds);
#else
glDrawRangeElements(glprim[prim], 0, indexGen.MaxIndex(), numTrans, GL_UNSIGNED_SHORT, inds);
#endif
} else {
glDrawArrays(glprim[prim], 0, numTrans);
}
} else if (result.action == SW_CLEAR) {
u32 clearColor = result.color;
float clearDepth = result.depth;
const float col[4] = {
((clearColor & 0xFF)) / 255.0f,
((clearColor & 0xFF00) >> 8) / 255.0f,
((clearColor & 0xFF0000) >> 16) / 255.0f,
((clearColor & 0xFF000000) >> 24) / 255.0f,
};
bool colorMask = gstate.isClearModeColorMask();
bool alphaMask = gstate.isClearModeAlphaMask();
bool depthMask = gstate.isClearModeDepthMask();
if (depthMask) {
framebufferManager_->SetDepthUpdated();
}
// Note that scissor may still apply while clearing. Turn off other tests for the clear.
glstate.stencilTest.disable();
glstate.stencilMask.set(0xFF);
glstate.depthTest.disable();
GLbitfield target = 0;
if (colorMask || alphaMask) target |= GL_COLOR_BUFFER_BIT;
if (alphaMask) target |= GL_STENCIL_BUFFER_BIT;
if (depthMask) target |= GL_DEPTH_BUFFER_BIT;
glClearColor(col[0], col[1], col[2], col[3]);
#ifdef USING_GLES2
glClearDepthf(clearDepth);
#else
glClearDepth(clearDepth);
#endif
// Stencil takes alpha.
glClearStencil(clearColor >> 24);
glClear(target);
framebufferManager_->SetColorUpdated();
}
} }
indexGen.Reset(); indexGen.Reset();

View File

@ -29,6 +29,7 @@ class LinkedShader;
class ShaderManager; class ShaderManager;
class TextureCache; class TextureCache;
class FramebufferManager; class FramebufferManager;
class FramebufferManagerCommon;
class FragmentTestCache; class FragmentTestCache;
struct TransformedVertex; struct TransformedVertex;
@ -95,6 +96,21 @@ public:
u8 flags; u8 flags;
}; };
enum SoftwareTransformAction {
SW_DRAW_PRIMITIVES,
SW_CLEAR,
};
struct SoftwareTransformResult {
SoftwareTransformAction action;
u32 color;
float depth;
bool setStencil;
u8 stencilValue;
};
// Handles transform, lighting and drawing. // Handles transform, lighting and drawing.
class TransformDrawEngine : public GfxResourceHolder { class TransformDrawEngine : public GfxResourceHolder {
public: public:
@ -177,7 +193,7 @@ private:
void DecodeVerts(); void DecodeVerts();
void DecodeVertsStep(); void DecodeVertsStep();
void DoFlush(); void DoFlush();
void SoftwareTransformAndDraw(int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertexType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex); void SoftwareTransform(int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertexType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex, FramebufferManagerCommon *fbman, TransformedVertex *&drawBuffer, int &numTrans, bool &drawIndexed, SoftwareTransformResult *result);
void ApplyDrawState(int prim); void ApplyDrawState(int prim);
void ApplyDrawStateLate(); void ApplyDrawStateLate();
void ApplyBlendState(); void ApplyBlendState();