Use a VAO for all drawing, and VBOs throughout.

This commit is contained in:
Unknown W. Brackets 2015-12-13 22:48:21 -08:00
parent b71061b1ef
commit 164594b044
7 changed files with 149 additions and 21 deletions

View File

@ -506,11 +506,18 @@ void FramebufferManager::DrawPlainColor(u32 color) {
glsl_bind(program);
glUniform4fv(plainColorLoc_, 1, col);
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glEnableVertexAttribArray(program->a_position);
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
transformDraw_->BindBuffer(pos, sizeof(pos));
transformDraw_->BindElementBuffer(indices, sizeof(indices));
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, 0);
} else {
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
}
glDisableVertexAttribArray(program->a_position);
glsl_unbind();
@ -525,7 +532,7 @@ void FramebufferManager::DrawActiveTexture(GLuint texture, float x, float y, flo
u0,v1,
};
static const GLushort indices[4] = {0,1,3,2};
static const GLubyte indices[4] = {0,1,3,2};
if (uvRotation != ROTATION_LOCKED_HORIZONTAL) {
float temp[8];
@ -582,13 +589,21 @@ void FramebufferManager::DrawActiveTexture(GLuint texture, float x, float y, flo
glsl_bind(program);
}
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glEnableVertexAttribArray(program->a_position);
glEnableVertexAttribArray(program->a_texcoord0);
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, texCoords);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
transformDraw_->BindBuffer(pos, sizeof(pos), texCoords, sizeof(texCoords));
transformDraw_->BindElementBuffer(indices, sizeof(indices));
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);
glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (void *)sizeof(pos));
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, 0);
} else {
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glVertexAttribPointer(program->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
glVertexAttribPointer(program->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, texCoords);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
}
glDisableVertexAttribArray(program->a_position);
glDisableVertexAttribArray(program->a_texcoord0);

View File

@ -411,6 +411,7 @@ GLES_GPU::GLES_GPU()
textureCache_.SetFramebufferManager(&framebufferManager_);
textureCache_.SetDepalShaderCache(&depalShaderCache_);
textureCache_.SetShaderManager(shaderManager_);
textureCache_.SetTransformDrawEngine(&transformDraw_);
fragmentTestCache_.SetTextureCache(&textureCache_);
// Sanity check gstate
@ -452,6 +453,7 @@ GLES_GPU::GLES_GPU()
// Some of our defaults are different from hw defaults, let's assert them.
// We restore each frame anyway, but here is convenient for tests.
transformDraw_.RestoreVAO();
glstate.Restore();
}
@ -503,6 +505,9 @@ void GLES_GPU::CheckGPUFeatures() {
if (gl_extensions.NV_framebuffer_blit) {
features |= GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT;
}
if (gl_extensions.ARB_vertex_array_object) {
features |= GPU_SUPPORTS_VAO;
}
bool useCPU = false;
if (!gl_extensions.IsGLES) {
@ -693,6 +698,7 @@ void GLES_GPU::UpdateCmdInfo() {
}
void GLES_GPU::ReapplyGfxStateInternal() {
transformDraw_.RestoreVAO();
glstate.Restore();
GPUCommon::ReapplyGfxStateInternal();
}
@ -708,6 +714,7 @@ void GLES_GPU::BeginFrameInternal() {
textureCache_.StartFrame();
transformDraw_.DecimateTrackedVertexArrays();
transformDraw_.DecimateBuffers();
depalShaderCache_.Decimate();
fragmentTestCache_.Decimate();

View File

@ -34,6 +34,7 @@
#include "GPU/GLES/FragmentShaderGenerator.h"
#include "GPU/GLES/DepalettizeShader.h"
#include "GPU/GLES/ShaderManager.h"
#include "GPU/GLES/TransformPipeline.h"
#include "GPU/Common/TextureDecoder.h"
#include "Core/Config.h"
#include "Core/Host.h"
@ -1112,8 +1113,13 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf
glUseProgram(depal->program);
// Restore will rebind all of the state below.
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
transformDraw_->BindBuffer(pos, sizeof(pos), uv, sizeof(uv));
transformDraw_->BindElementBuffer(indices, sizeof(indices));
} else {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glEnableVertexAttribArray(depal->a_position);
glEnableVertexAttribArray(depal->a_texcoord0);
@ -1136,9 +1142,15 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf
#endif
glViewport(0, 0, framebuffer->renderWidth, framebuffer->renderHeight);
glVertexAttribPointer(depal->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
glVertexAttribPointer(depal->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
glVertexAttribPointer(depal->a_position, 3, GL_FLOAT, GL_FALSE, 12, 0);
glVertexAttribPointer(depal->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, (void *)sizeof(pos));
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, 0);
} else {
glVertexAttribPointer(depal->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
glVertexAttribPointer(depal->a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
}
glDisableVertexAttribArray(depal->a_position);
glDisableVertexAttribArray(depal->a_texcoord0);

View File

@ -32,6 +32,7 @@ struct VirtualFramebuffer;
class FramebufferManager;
class DepalShaderCache;
class ShaderManager;
class TransformDrawEngine;
enum FramebufferNotification {
NOTIFY_FB_CREATED,
@ -75,6 +76,9 @@ public:
void SetShaderManager(ShaderManager *sm) {
shaderManager_ = sm;
}
void SetTransformDrawEngine(TransformDrawEngine *td) {
transformDraw_ = td;
}
size_t NumLoadedTextures() const {
return cache.size();
@ -164,6 +168,7 @@ private:
FramebufferManager *framebufferManager_;
DepalShaderCache *depalShaderCache_;
ShaderManager *shaderManager_;
TransformDrawEngine *transformDraw_;
};
GLenum getClutDestFormat(GEPaletteFormat format);

View File

@ -161,10 +161,27 @@ TransformDrawEngine::~TransformDrawEngine() {
delete [] uvScale;
}
void TransformDrawEngine::RestoreVAO() {
if (sharedVao_ != 0) {
glBindVertexArray(sharedVao_);
} else if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
// Note: this is here because, InitDeviceObjects() is called before GPU_SUPPORTS_VAO is setup.
// So, this establishes it if Supports() returns true and there isn't one yet.
glGenVertexArrays(1, &sharedVao_);
glBindVertexArray(sharedVao_);
}
}
void TransformDrawEngine::InitDeviceObjects() {
if (bufferNameCache_.empty()) {
bufferNameCache_.resize(VERTEXCACHE_NAME_CACHE_SIZE);
glGenBuffers(VERTEXCACHE_NAME_CACHE_SIZE, &bufferNameCache_[0]);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
glGenVertexArrays(1, &sharedVao_);
} else {
sharedVao_ = 0;
}
} else {
ERROR_LOG(G3D, "Device objects already initialized!");
}
@ -176,6 +193,10 @@ void TransformDrawEngine::DestroyDeviceObjects() {
glstate.elementArrayBuffer.unbind();
glDeleteBuffers((GLsizei)bufferNameCache_.size(), &bufferNameCache_[0]);
bufferNameCache_.clear();
if (sharedVao_ != 0) {
glDeleteVertexArrays(1, &sharedVao_);
}
}
ClearTrackedVertexArrays();
}
@ -763,6 +784,13 @@ rotateVBO:
prim = indexGen.Prim();
}
if (gstate_c.Supports(GPU_SUPPORTS_VAO) && vbo == 0) {
vbo = BindBuffer(decoded, dec_->GetDecVtxFmt().stride * indexGen.MaxIndex());
if (useElements) {
ebo = BindElementBuffer(decIndex, sizeof(short) * indexGen.VertexCount());
}
}
VERBOSE_LOG(G3D, "Flush prim %i! %i verts in one go", prim, vertexCount);
bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;
if (gstate.isModeThrough()) {
@ -818,13 +846,25 @@ rotateVBO:
const int vertexSize = sizeof(transformed[0]);
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glVertexAttribPointer(ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, drawBuffer);
const uint8_t *bufferStart = (const uint8_t *)drawBuffer;
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
bufferStart = 0;
BindBuffer(drawBuffer, vertexSize * maxIndex);
if (drawIndexed) {
BindElementBuffer(inds, sizeof(short) * numTrans);
inds = 0;
}
} else {
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
}
glVertexAttribPointer(ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, vertexSize, bufferStart);
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 (attrMask & (1 << ATTR_TEXCOORD)) glVertexAttribPointer(ATTR_TEXCOORD, doTextureProjection ? 3 : 2, GL_FLOAT, GL_FALSE, vertexSize, bufferStart + offsetof(TransformedVertex, u));
if (attrMask & (1 << ATTR_COLOR0)) glVertexAttribPointer(ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, bufferStart + offsetof(TransformedVertex, color0));
if (attrMask & (1 << ATTR_COLOR1)) glVertexAttribPointer(ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, vertexSize, bufferStart + offsetof(TransformedVertex, color1));
if (drawIndexed) {
glDrawElements(glprim[prim], numTrans, GL_UNSIGNED_SHORT, inds);
} else {
@ -912,6 +952,46 @@ void TransformDrawEngine::Resized() {
}
}
GLuint TransformDrawEngine::BindBuffer(const void *p, size_t sz) {
// Get a new buffer each time we need one.
GLuint buf = AllocateBuffer();
glstate.arrayBuffer.bind(buf);
// These aren't used more than once per frame, so let's use GL_STREAM_DRAW.
glBufferData(GL_ARRAY_BUFFER, sz, p, GL_STREAM_DRAW);
buffersThisFrame_.push_back(buf);
return buf;
}
GLuint TransformDrawEngine::BindBuffer(const void *p1, size_t sz1, const void *p2, size_t sz2) {
GLuint buf = AllocateBuffer();
glstate.arrayBuffer.bind(buf);
glBufferData(GL_ARRAY_BUFFER, sz1 + sz2, nullptr, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sz1, p1);
glBufferSubData(GL_ARRAY_BUFFER, sz1, sz2, p2);
buffersThisFrame_.push_back(buf);
return buf;
}
GLuint TransformDrawEngine::BindElementBuffer(const void *p, size_t sz) {
GLuint buf = AllocateBuffer();
glstate.elementArrayBuffer.bind(buf);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sz, p, GL_STREAM_DRAW);
buffersThisFrame_.push_back(buf);
return buf;
}
void TransformDrawEngine::DecimateBuffers() {
for (GLuint buf : buffersThisFrame_) {
FreeBuffer(buf);
}
buffersThisFrame_.clear();
}
bool TransformDrawEngine::IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
}

View File

@ -127,6 +127,7 @@ public:
void SetFragmentTestCache(FragmentTestCache *testCache) {
fragmentTestCache_ = testCache;
}
void RestoreVAO();
void InitDeviceObjects();
void DestroyDeviceObjects();
void GLLost() override;
@ -188,6 +189,11 @@ public:
SubmitPrim(verts, inds, prim, vertexCount, vertType, bytesRead);
}
GLuint BindBuffer(const void *p, size_t sz);
GLuint BindBuffer(const void *p1, size_t sz1, const void *p2, size_t sz2);
GLuint BindElementBuffer(const void *p, size_t sz);
void DecimateBuffers();
private:
void DecodeVerts();
void DecodeVertsStep();
@ -232,6 +238,8 @@ private:
// Vertex buffer objects
// Element buffer objects
std::vector<GLuint> bufferNameCache_;
std::vector<GLuint> buffersThisFrame_;
GLuint sharedVao_;
// Other
ShaderManager *shaderManager_;

View File

@ -454,6 +454,7 @@ enum {
GPU_SUPPORTS_BLEND_MINMAX = FLAG_BIT(4),
GPU_SUPPORTS_LOGIC_OP = FLAG_BIT(5),
GPU_USE_DEPTH_RANGE_HACK = FLAG_BIT(6),
GPU_SUPPORTS_VAO = FLAG_BIT(18),
GPU_SUPPORTS_ANY_COPY_IMAGE = FLAG_BIT(19),
GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20),
GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22),