Delete the gl name cache (might resurrect it on the GLQueueRunner side if needed later). Other cleanup and fixes.

This commit is contained in:
Henrik Rydgård 2017-12-12 14:07:52 +01:00
parent 46e1fbb788
commit f3282dcfda
12 changed files with 185 additions and 405 deletions

View file

@ -206,7 +206,7 @@ public:
return vfb;
}
}
virtual void RebindFramebuffer();
void RebindFramebuffer();
std::vector<FramebufferInfo> GetFramebufferList();
void CopyDisplayToOutput();

View file

@ -58,8 +58,7 @@ public:
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
virtual void RebindFramebuffer() override;
void RebindFramebuffer();
// TODO: Remove
ID3D11Buffer *GetDynamicQuadBuffer() {

View file

@ -91,7 +91,7 @@
#include "GPU/GLES/ShaderManagerGLES.h"
#include "GPU/GLES/GPU_GLES.h"
extern const GLuint glprim[8] = {
const GLuint glprim[8] = {
GL_POINTS,
GL_LINES,
GL_LINE_STRIP,
@ -146,17 +146,6 @@ DrawEngineGLES::~DrawEngineGLES() {
delete tessDataTransfer;
}
void DrawEngineGLES::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 DrawEngineGLES::DeviceLost() {
DestroyDeviceObjects();
}
@ -166,20 +155,6 @@ void DrawEngineGLES::DeviceRestore() {
}
void DrawEngineGLES::InitDeviceObjects() {
if (bufferNameCache_.empty()) {
bufferNameCache_.resize(VERTEXCACHE_NAME_CACHE_SIZE);
glGenBuffers(VERTEXCACHE_NAME_CACHE_SIZE, &bufferNameCache_[0]);
bufferNameCacheSize_ = 0;
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
glGenVertexArrays(1, &sharedVao_);
} else {
sharedVao_ = 0;
}
} else {
ERROR_LOG(G3D, "Device objects already initialized!");
}
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].pushVertex = new GLPushBuffer(render_, GL_ARRAY_BUFFER, 1024 * 1024);
frameData_[i].pushIndex = new GLPushBuffer(render_, GL_ELEMENT_ARRAY_BUFFER, 512 * 1024);
@ -203,18 +178,6 @@ void DrawEngineGLES::DestroyDeviceObjects() {
}
ClearTrackedVertexArrays();
if (!bufferNameCache_.empty()) {
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glDeleteBuffers((GLsizei)bufferNameCache_.size(), &bufferNameCache_[0]);
bufferNameCache_.clear();
bufferNameInfo_.clear();
freeSizedBuffers_.clear();
bufferNameCacheSize_ = 0;
if (sharedVao_ != 0) {
glDeleteVertexArrays(1, &sharedVao_);
}
}
render_->DeleteInputLayout(softwareInputLayout_);
}
@ -376,11 +339,11 @@ void DrawEngineGLES::DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindO
void DrawEngineGLES::MarkUnreliable(VertexArrayInfo *vai) {
vai->status = VertexArrayInfo::VAI_UNRELIABLE;
if (vai->vbo) {
FreeBuffer(vai->vbo);
render_->DeleteBuffer(vai->vbo);
vai->vbo = 0;
}
if (vai->ebo) {
FreeBuffer(vai->ebo);
render_->DeleteBuffer(vai->ebo);
vai->ebo = 0;
}
}
@ -420,80 +383,14 @@ void DrawEngineGLES::DecimateTrackedVertexArrays() {
vai_.Maintain();
}
GLuint DrawEngineGLES::AllocateBuffer(size_t sz) {
GLuint unused = 0;
auto freeMatch = freeSizedBuffers_.find(sz);
if (freeMatch != freeSizedBuffers_.end()) {
unused = freeMatch->second;
_assert_(!bufferNameInfo_[unused].used);
freeSizedBuffers_.erase(freeMatch);
} else {
for (GLuint buf : bufferNameCache_) {
const BufferNameInfo &info = bufferNameInfo_[buf];
if (info.used) {
continue;
}
// Just pick the first unused one, we'll have to resize it.
unused = buf;
// Let's also remove from the free list, if it's there.
if (info.sz != 0) {
auto range = freeSizedBuffers_.equal_range(info.sz);
for (auto it = range.first; it != range.second; ++it) {
if (it->second == buf) {
// It will only be once, so remove and bail.
freeSizedBuffers_.erase(it);
break;
}
}
}
break;
}
}
if (unused == 0) {
size_t oldSize = bufferNameCache_.size();
bufferNameCache_.resize(oldSize + VERTEXCACHE_NAME_CACHE_SIZE);
glGenBuffers(VERTEXCACHE_NAME_CACHE_SIZE, &bufferNameCache_[oldSize]);
unused = bufferNameCache_[oldSize];
}
BufferNameInfo &info = bufferNameInfo_[unused];
// Record the change in size.
bufferNameCacheSize_ += sz - info.sz;
info.sz = sz;
info.used = true;
return unused;
}
void DrawEngineGLES::FreeBuffer(GLuint buf) {
// We can reuse buffers by setting new data on them, so let's actually keep it.
auto it = bufferNameInfo_.find(buf);
if (it != bufferNameInfo_.end()) {
it->second.used = false;
it->second.lastFrame = gpuStats.numFlips;
if (it->second.sz != 0) {
freeSizedBuffers_.insert(std::make_pair(it->second.sz, buf));
}
} else {
ERROR_LOG(G3D, "Unexpected buffer freed (%d) but not tracked", buf);
}
}
void DrawEngineGLES::FreeVertexArray(VertexArrayInfo *vai) {
if (vai->vbo) {
FreeBuffer(vai->vbo);
vai->vbo = 0;
render_->DeleteBuffer(vai->vbo);
vai->vbo = nullptr;
}
if (vai->ebo) {
FreeBuffer(vai->ebo);
vai->ebo = 0;
render_->DeleteBuffer(vai->ebo);
vai->ebo = nullptr;
}
}
@ -517,7 +414,6 @@ void DrawEngineGLES::DoFlush() {
uint32_t indexBufferOffset = 0;
if (vshader->UseHWTransform()) {
GLuint vbo = 0, ebo = 0;
int vertexCount = 0;
bool useElements = true;
@ -611,31 +507,28 @@ void DrawEngineGLES::DoFlush() {
_dbg_assert_msg_(G3D, gstate_c.vertBounds.minV >= gstate_c.vertBounds.maxV, "Should not have checked UVs when caching.");
size_t vsz = dec_->GetDecVtxFmt().stride * indexGen.MaxIndex();
vai->vbo = AllocateBuffer(vsz);
glstate.arrayBuffer.bind(vai->vbo);
glBufferData(GL_ARRAY_BUFFER, vsz, decoded, GL_STATIC_DRAW);
vai->vbo = render_->CreateBuffer(GL_ARRAY_BUFFER, vsz, GL_STATIC_DRAW);
render_->BufferSubdata(vai->vbo, 0, vsz, decoded);
render_->BindVertexBuffer(vai->vbo);
// If there's only been one primitive type, and it's either TRIANGLES, LINES or POINTS,
// there is no need for the index buffer we built. We can then use glDrawArrays instead
// for a very minor speed boost.
if (useElements) {
size_t esz = sizeof(short) * indexGen.VertexCount();
vai->ebo = AllocateBuffer(esz);
glstate.elementArrayBuffer.bind(vai->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, esz, (GLvoid *)decIndex, GL_STATIC_DRAW);
vai->ebo = render_->CreateBuffer(GL_ARRAY_BUFFER, esz, GL_STATIC_DRAW);
render_->BufferSubdata(vai->ebo, 0, esz, (uint8_t *)decIndex, false);
} else {
vai->ebo = 0;
glstate.elementArrayBuffer.bind(vai->ebo);
render_->BindIndexBuffer(vai->ebo);
}
} else {
gpuStats.numCachedDrawCalls++;
glstate.arrayBuffer.bind(vai->vbo);
glstate.elementArrayBuffer.bind(vai->ebo);
useElements = vai->ebo ? true : false;
gpuStats.numCachedVertsDrawn += vai->numVerts;
gstate_c.vertexFullAlpha = vai->flags & VAI_FLAG_VERTEXFULLALPHA;
}
vbo = vai->vbo;
ebo = vai->ebo;
vertexBuffer = vai->vbo;
indexBuffer = vai->ebo;
vertexCount = vai->numVerts;
prim = static_cast<GEPrimitiveType>(vai->prim);
break;
@ -650,10 +543,8 @@ void DrawEngineGLES::DoFlush() {
}
gpuStats.numCachedDrawCalls++;
gpuStats.numCachedVertsDrawn += vai->numVerts;
vbo = vai->vbo;
ebo = vai->ebo;
glstate.arrayBuffer.bind(vbo);
glstate.elementArrayBuffer.bind(ebo);
vertexBuffer = vai->vbo;
indexBuffer = vai->ebo;
vertexCount = vai->numVerts;
prim = static_cast<GEPrimitiveType>(vai->prim);
@ -843,108 +734,12 @@ rotateVBO:
CHECK_GL_ERROR_IF_DEBUG();
}
GLuint DrawEngineGLES::BindBuffer(const void *p, size_t sz) {
// Get a new buffer each time we need one.
GLuint buf = AllocateBuffer(sz);
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 DrawEngineGLES::BindBuffer(const void *p1, size_t sz1, const void *p2, size_t sz2) {
GLuint buf = AllocateBuffer(sz1 + sz2);
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 DrawEngineGLES::BindElementBuffer(const void *p, size_t sz) {
GLuint buf = AllocateBuffer(sz);
glstate.elementArrayBuffer.bind(buf);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sz, p, GL_STREAM_DRAW);
buffersThisFrame_.push_back(buf);
return buf;
}
void DrawEngineGLES::DecimateBuffers() {
for (GLuint buf : buffersThisFrame_) {
FreeBuffer(buf);
}
buffersThisFrame_.clear();
if (--bufferDecimationCounter_ <= 0) {
bufferDecimationCounter_ = VERTEXCACHE_DECIMATION_INTERVAL;
} else {
return;
}
// Let's not keep too many around, will eat up memory.
// First check if there's any to free, and only check if it seems somewhat full.
bool hasOld = false;
if (bufferNameCacheSize_ > VERTEXCACHE_NAME_CACHE_FULL_BYTES) {
for (GLuint buf : bufferNameCache_) {
const BufferNameInfo &info = bufferNameInfo_[buf];
const int age = gpuStats.numFlips - info.lastFrame;
if (!info.used && age > VERTEXCACHE_NAME_CACHE_MAX_AGE) {
hasOld = true;
break;
}
}
}
if (hasOld) {
// Okay, it is. Let's rebuild the array.
std::vector<GLuint> toFree;
std::vector<GLuint> toKeep;
toKeep.reserve(bufferNameCache_.size());
for (size_t i = 0, n = bufferNameCache_.size(); i < n; ++i) {
const GLuint buf = bufferNameCache_[i];
const BufferNameInfo &info = bufferNameInfo_[buf];
const int age = gpuStats.numFlips - info.lastFrame;
if (!info.used && age > VERTEXCACHE_NAME_CACHE_MAX_AGE) {
toFree.push_back(buf);
bufferNameCacheSize_ -= bufferNameInfo_[buf].sz;
bufferNameInfo_.erase(buf);
// If we've removed all we want to this round, keep the rest and abort.
if (toFree.size() >= VERTEXCACHE_NAME_DECIMATION_MAX && i + 1 < bufferNameCache_.size()) {
toKeep.insert(toKeep.end(), bufferNameCache_.begin() + i + 1, bufferNameCache_.end());
break;
}
} else {
toKeep.push_back(buf);
}
}
if (!toFree.empty()) {
bufferNameCache_ = toKeep;
// TODO: Rebuild?
freeSizedBuffers_.clear();
glstate.arrayBuffer.unbind();
glstate.elementArrayBuffer.unbind();
glDeleteBuffers((GLsizei)toFree.size(), &toFree[0]);
}
}
}
bool DrawEngineGLES::IsCodePtrVertexDecoder(const u8 *ptr) const {
return decJitCache_->IsInSpace(ptr);
}
void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) {
/*
#ifndef USING_GLES2
if (isAllowTexture1D_) {
// Position
@ -1041,4 +836,5 @@ void DrawEngineGLES::TessellationDataTransferGLES::SendDataToShader(const float
}
glActiveTexture(GL_TEXTURE0);
CHECK_GL_ERROR_IF_DEBUG();
*/
}

View file

@ -61,8 +61,8 @@ class VertexArrayInfo {
public:
VertexArrayInfo() {
status = VAI_NEW;
vbo = 0;
ebo = 0;
vbo = nullptr;
ebo = nullptr;
prim = GE_PRIM_INVALID;
numDraws = 0;
numFrames = 0;
@ -82,8 +82,8 @@ public:
ReliableHashType hash;
u32 minihash;
u32 vbo;
u32 ebo;
GLRBuffer *vbo;
GLRBuffer *ebo;
// Precalculated parameter for drawRangeElements
u16 numVerts;
@ -119,7 +119,6 @@ public:
void SetFragmentTestCache(FragmentTestCacheGLES *testCache) {
fragmentTestCache_ = testCache;
}
void RestoreVAO();
void DeviceLost();
void DeviceRestore();
@ -151,10 +150,12 @@ 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();
GLPushBuffer *GetPushVertexBuffer() {
return frameData_[render_->GetCurFrame()].pushVertex;
}
GLPushBuffer *GetPushIndexBuffer() {
return frameData_[render_->GetCurFrame()].pushIndex;
}
void ClearInputLayoutMap();
@ -171,8 +172,6 @@ private:
void DecodeVertsToPushBuffer(GLPushBuffer *push, uint32_t *bindOffset, GLRBuffer **buf);
GLuint AllocateBuffer(size_t sz);
void FreeBuffer(GLuint buf);
void FreeVertexArray(VertexArrayInfo *vai);
void MarkUnreliable(VertexArrayInfo *vai);
@ -188,23 +187,7 @@ private:
DenseHashMap<uint32_t, GLRInputLayout *, nullptr> inputLayoutMap_;
GLRInputLayout *softwareInputLayout_ = nullptr;
// Vertex buffer objects
// Element buffer objects
struct BufferNameInfo {
BufferNameInfo() : sz(0), used(false), lastFrame(0) {}
size_t sz;
bool used;
int lastFrame;
};
GLRenderManager *render_;
std::vector<GLuint> bufferNameCache_;
std::multimap<size_t, GLuint> freeSizedBuffers_;
std::unordered_map<GLuint, BufferNameInfo> bufferNameInfo_;
std::vector<GLuint> buffersThisFrame_;
size_t bufferNameCacheSize_ = 0;
GLuint sharedVao_ = 0;
// Other
ShaderManagerGLES *shaderManager_ = nullptr;
@ -218,15 +201,11 @@ private:
// Hardware tessellation
class TessellationDataTransferGLES : public TessellationDataTransfer {
private:
int data_tex[3];
GLRTexture *data_tex[3]{};
bool isAllowTexture1D_;
public:
TessellationDataTransferGLES(bool isAllowTexture1D) : TessellationDataTransfer(), data_tex(), isAllowTexture1D_(isAllowTexture1D) {
glGenTextures(3, (GLuint*)data_tex);
}
~TessellationDataTransferGLES() {
glDeleteTextures(3, (GLuint*)data_tex);
}
TessellationDataTransferGLES(bool isAllowTexture1D) : TessellationDataTransfer(), isAllowTexture1D_(isAllowTexture1D) { }
~TessellationDataTransferGLES() { }
void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override;
};
};

View file

@ -42,7 +42,6 @@
#include "GPU/Common/TextureDecoder.h"
#include "GPU/Common/FramebufferCommon.h"
#include "GPU/Debugger/Stepping.h"
#include "ext/native/gfx/GLStateCache.h"
#include "GPU/GLES/FramebufferManagerGLES.h"
#include "GPU/GLES/TextureCacheGLES.h"
#include "GPU/GLES/DrawEngineGLES.h"
@ -103,13 +102,14 @@ void FramebufferManagerGLES::CompileDraw2DProgram() {
static std::string vs_code, fs_code;
vs_code = ApplyGLSLPrelude(basic_vs, GL_VERTEX_SHADER);
fs_code = ApplyGLSLPrelude(tex_fs, GL_FRAGMENT_SHADER);
draw2dprogram_ = glsl_create_source(vs_code.c_str(), fs_code.c_str(), &errorString);
if (!draw2dprogram_) {
ERROR_LOG_REPORT(G3D, "Failed to compile draw2dprogram! This shouldn't happen.\n%s", errorString.c_str());
} else {
glsl_bind(draw2dprogram_);
glUniform1i(draw2dprogram_->sampler0, 0);
}
std::vector<GLRShader *> shaders;
GLRShader *vs = render_->CreateShader(GL_VERTEX_SHADER, vs_code);
GLRShader *fs = render_->CreateShader(GL_FRAGMENT_SHADER, fs_code);
std::vector<GLRProgram::UniformLocQuery> queries;
queries.push_back({ &u_draw2d_tex, "u_tex" });
std::vector<GLRProgram::Initializer> initializers;
initializers.push_back({ &u_draw2d_tex, 0 });
draw2dprogram_ = render_->CreateProgram(shaders, {}, queries, initializers, false);
CompilePostShader();
}
}
@ -156,7 +156,26 @@ void FramebufferManagerGLES::CompilePostShader() {
}
if (!translationFailed) {
postShaderProgram_ = glsl_create_source(vshader.c_str(), fshader.c_str(), &errorString);
SetNumExtraFBOs(1);
std::vector<GLRShader *> shaders;
shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vshader));
shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, fshader));
std::vector<GLRProgram::UniformLocQuery> queries;
queries.push_back({ &u_postShaderTex, "tex" });
queries.push_back({ &deltaLoc_, "u_texelDelta" });
queries.push_back({ &pixelDeltaLoc_, "u_pixelDelta" });
queries.push_back({ &timeLoc_, "u_time" });
queries.push_back({ &videoLoc_, "u_video" });
std::vector<GLRProgram::Initializer> inits;
inits.push_back({ &u_postShaderTex, 0, 0 });
postShaderProgram_ = render_->CreateProgram(shaders, {}, queries, inits, false);
render_->SetUniformI1(&u_postShaderTex, 0);
for (auto iter : shaders) {
render_->DeleteShader(iter);
}
} else {
ERROR_LOG(FRAMEBUF, "Failed to translate post shader!");
}
@ -194,13 +213,6 @@ void FramebufferManagerGLES::CompilePostShader() {
}
usePostShader_ = false;
} else {
glsl_bind(postShaderProgram_);
glUniform1i(postShaderProgram_->sampler0, 0);
SetNumExtraFBOs(1);
deltaLoc_ = glsl_uniform_loc(postShaderProgram_, "u_texelDelta");
pixelDeltaLoc_ = glsl_uniform_loc(postShaderProgram_, "u_pixelDelta");
timeLoc_ = glsl_uniform_loc(postShaderProgram_, "u_time");
videoLoc_ = glsl_uniform_loc(postShaderProgram_, "u_video");
usePostShader_ = true;
}
} else {
@ -211,7 +223,7 @@ void FramebufferManagerGLES::CompilePostShader() {
}
void FramebufferManagerGLES::Bind2DShader() {
glsl_bind(draw2dprogram_);
render_->BindProgram(draw2dprogram_);
}
void FramebufferManagerGLES::BindPostShader(const PostShaderUniforms &uniforms) {
@ -219,20 +231,20 @@ void FramebufferManagerGLES::BindPostShader(const PostShaderUniforms &uniforms)
if (!postShaderProgram_) {
CompileDraw2DProgram();
}
glsl_bind(postShaderProgram_);
render_->BindProgram(postShaderProgram_);
if (deltaLoc_ != -1)
glUniform2f(deltaLoc_, uniforms.texelDelta[0], uniforms.texelDelta[1]);
render_->SetUniformF(&deltaLoc_, 2, uniforms.texelDelta);
if (pixelDeltaLoc_ != -1)
glUniform2f(pixelDeltaLoc_, uniforms.pixelDelta[0], uniforms.pixelDelta[1]);
render_->SetUniformF(&pixelDeltaLoc_, 2, uniforms.pixelDelta);
if (timeLoc_ != -1)
glUniform4fv(timeLoc_, 1, uniforms.time);
render_->SetUniformF(&timeLoc_, 4, uniforms.time);
if (videoLoc_ != -1)
glUniform1f(videoLoc_, uniforms.video);
render_->SetUniformF(&videoLoc_, 1, &uniforms.video);
}
FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw) :
FramebufferManagerGLES::FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render) :
FramebufferManagerCommon(draw),
render_(render),
drawPixelsTex_(0),
drawPixelsTexFormat_(GE_FORMAT_INVALID),
convBuf_(nullptr),
@ -275,15 +287,25 @@ void FramebufferManagerGLES::SetDrawEngine(DrawEngineGLES *td) {
void FramebufferManagerGLES::CreateDeviceObjects() {
CompileDraw2DProgram();
std::vector<GLRInputLayout::Entry> entries;
entries.push_back({ 0, 3, GL_FLOAT, GL_FALSE, sizeof(Simple2DVertex), offsetof(Simple2DVertex, pos) });
entries.push_back({ 0, 2, GL_FLOAT, GL_FALSE, sizeof(Simple2DVertex), offsetof(Simple2DVertex, uv) });
simple2DInputLayout_ = render_->CreateInputLayout(entries);
}
void FramebufferManagerGLES::DestroyDeviceObjects() {
if (simple2DInputLayout_) {
render_->DeleteInputLayout(simple2DInputLayout_);
simple2DInputLayout_ = nullptr;
}
if (draw2dprogram_) {
glsl_destroy(draw2dprogram_);
render_->DeleteProgram(draw2dprogram_);
draw2dprogram_ = nullptr;
}
if (postShaderProgram_) {
glsl_destroy(postShaderProgram_);
render_->DeleteProgram(postShaderProgram_);
postShaderProgram_ = nullptr;
}
if (drawPixelsTex_) {
@ -291,7 +313,7 @@ void FramebufferManagerGLES::DestroyDeviceObjects() {
drawPixelsTex_ = 0;
}
if (stencilUploadProgram_) {
glsl_destroy(stencilUploadProgram_);
render_->DeleteProgram(stencilUploadProgram_);
stencilUploadProgram_ = nullptr;
}
}
@ -329,15 +351,10 @@ void FramebufferManagerGLES::MakePixelTexture(const u8 *srcPixels, GEBufferForma
drawPixelsTexW_ = texWidth;
drawPixelsTexH_ = height;
/*
// Initialize backbuffer texture for DrawPixels
glBindTexture(GL_TEXTURE_2D, drawPixelsTex_);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
render_->BindTexture(0, drawPixelsTex_);
render_->SetTextureSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f);
/*
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
*/
drawPixelsTexFormat_ = srcPixelFormat;
@ -392,7 +409,7 @@ void FramebufferManagerGLES::MakePixelTexture(const u8 *srcPixels, GEBufferForma
}
void FramebufferManagerGLES::SetViewport2D(int x, int y, int w, int h) {
glstate.viewport.set(x, y, w, h);
render_->SetViewport({ (float)x, (float)y, (float)w, (float)h, 0.0f, 1.0f });
}
// x, y, w, h are relative coordinates against destW/destH, which is not very intuitive.
@ -405,7 +422,7 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float
u0,v1,
};
static const GLushort indices[4] = {0,1,3,2};
static const GLushort indices[4] = { 0,1,3,2 };
if (uvRotation != ROTATION_LOCKED_HORIZONTAL) {
float temp[8];
@ -424,9 +441,9 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float
float pos[12] = {
x,y,0,
x+w,y,0,
x+w,y+h,0,
x,y+h,0
x + w,y,0,
x + w,y + h,0,
x,y + h,0
};
float invDestW = 1.0f / (destW * 0.5f);
@ -438,11 +455,9 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float
// Upscaling postshaders doesn't look well with linear
if (flags & DRAWTEX_LINEAR) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
render_->SetTextureSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR, 0.0f);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
render_->SetTextureSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f);
}
const GLSLProgram *program = glsl_get_program();
@ -450,30 +465,23 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float
ERROR_LOG(FRAMEBUF, "Trying to DrawActiveTexture() without a program");
return;
}
Simple2DVertex verts[4];
memcpy(verts[0].pos, &pos[0], 12);
memcpy(verts[1].pos, &pos[3], 12);
memcpy(verts[3].pos, &pos[6], 12);
memcpy(verts[2].pos, &pos[9], 12);
memcpy(verts[0].uv, &texCoords[0], 8);
memcpy(verts[1].uv, &texCoords[2], 8);
memcpy(verts[3].uv, &texCoords[4], 8);
memcpy(verts[2].uv, &texCoords[6], 8);
glEnableVertexAttribArray(program->a_position);
glEnableVertexAttribArray(program->a_texcoord0);
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
drawEngineGL_->BindBuffer(pos, sizeof(pos), texCoords, sizeof(texCoords));
drawEngineGL_->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_SHORT, 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_SHORT, indices);
}
glDisableVertexAttribArray(program->a_position);
glDisableVertexAttribArray(program->a_texcoord0);
}
void FramebufferManagerGLES::RebindFramebuffer() {
FramebufferManagerCommon::RebindFramebuffer();
if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE)
glstate.viewport.restore();
uint32_t bindOffset;
GLRBuffer *buffer;
void *dest = drawEngineGL_->GetPushVertexBuffer()->Push(sizeof(verts), &bindOffset, &buffer);
memcpy(dest, verts, sizeof(verts));
render_->BindVertexBuffer(buffer);
render_->BindInputLayout(simple2DInputLayout_, (void *)(intptr_t)bindOffset);
render_->Draw(GL_TRIANGLE_STRIP, 0, 4);
}
void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) {
@ -514,17 +522,15 @@ void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, Virtu
if (gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT)) {
// Let's only do this if not clearing depth.
glstate.scissorTest.force(false);
draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST);
dst->last_frame_depth_updated = gpuStats.numFlips;
glstate.scissorTest.restore();
}
}
}
void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
if (!framebuffer->fbo || !useBufferedRendering_) {
glBindTexture(GL_TEXTURE_2D, 0);
render_->BindTexture(0, nullptr);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return;
}
@ -691,7 +697,6 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX,
}
}
glstate.scissorTest.force(false);
if (useBlit) {
draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST);
} else {
@ -701,38 +706,21 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX,
// Make sure our 2D drawing program is ready. Compiles only if not already compiled.
CompileDraw2DProgram();
glstate.viewport.force(0, 0, dst->renderWidth, dst->renderHeight);
glstate.blend.force(false);
glstate.cullFace.force(false);
glstate.depthTest.force(false);
glstate.stencilTest.force(false);
#if !defined(USING_GLES2)
glstate.colorLogicOp.force(false);
#endif
glstate.colorMask.force(true, true, true, true);
glstate.stencilMask.force(0xFF);
render_->SetViewport({ 0, 0, (float)dst->renderWidth, (float)dst->renderHeight, 0, 1.0f });
render_->SetStencilDisabled();
render_->SetDepth(false, false, GL_ALWAYS);
render_->SetNoBlendAndMask(0xF);
// The first four coordinates are relative to the 6th and 7th arguments of DrawActiveTexture.
// Should maybe revamp that interface.
float srcW = src->bufferWidth;
float srcH = src->bufferHeight;
glsl_bind(draw2dprogram_);
render_->BindProgram(draw2dprogram_);
DrawActiveTexture(dstX1, dstY1, w * dstXFactor, h, dst->bufferWidth, dst->bufferHeight, srcX1 / srcW, srcY1 / srcH, srcX2 / srcW, srcY2 / srcH, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
textureCacheGL_->ForgetLastTexture();
glstate.viewport.restore();
glstate.blend.restore();
glstate.cullFace.restore();
glstate.depthTest.restore();
glstate.stencilTest.restore();
#if !defined(USING_GLES2)
glstate.colorLogicOp.restore();
#endif
glstate.colorMask.restore();
glstate.stencilMask.restore();
}
glstate.scissorTest.restore();
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE);
CHECK_GL_ERROR_IF_DEBUG();
}

View file

@ -51,7 +51,7 @@ struct AsyncPBO {
class FramebufferManagerGLES : public FramebufferManagerCommon {
public:
FramebufferManagerGLES(Draw::DrawContext *draw);
FramebufferManagerGLES(Draw::DrawContext *draw, GLRenderManager *render);
~FramebufferManagerGLES();
void SetTextureCache(TextureCacheGLES *tc);
@ -82,7 +82,6 @@ public:
bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override;
bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;
virtual void RebindFramebuffer() override;
void DeviceRestore(Draw::DrawContext *draw);
@ -104,7 +103,6 @@ private:
void Bind2DShader() override;
void BindPostShader(const PostShaderUniforms &uniforms) override;
void CompileDraw2DProgram();
void DestroyDraw2DProgram();
void CompilePostShader();
void PackFramebufferAsync_(VirtualFramebuffer *vfb); // Not used under ES currently
@ -121,19 +119,34 @@ private:
u8 *convBuf_;
u32 convBufSize_;
GLSLProgram *draw2dprogram_ = nullptr;
GLSLProgram *postShaderProgram_ = nullptr;
GLSLProgram *stencilUploadProgram_ = nullptr;
int plainColorLoc_;
int videoLoc_;
int timeLoc_;
int pixelDeltaLoc_;
int deltaLoc_;
GLRProgram *draw2dprogram_ = nullptr;
GLRProgram *postShaderProgram_ = nullptr;
GLRProgram *stencilUploadProgram_ = nullptr;
int u_stencilUploadTex = -1;
int u_stencilValue = -1;
int u_postShaderTex = -1;
// Cached uniform locs
int u_draw2d_tex = -1;
int plainColorLoc_ = -1;
int videoLoc_ = -1;
int timeLoc_ = -1;
int pixelDeltaLoc_ = -1;
int deltaLoc_ = -1;
TextureCacheGLES *textureCacheGL_;
ShaderManagerGLES *shaderManagerGL_;
DrawEngineGLES *drawEngineGL_;
struct Simple2DVertex {
float pos[3];
float uv[2];
};
GLRInputLayout *simple2DInputLayout_;
// Not used under ES currently.
AsyncPBO *pixelBufObj_; //this isn't that large
u8 currentPBO_;

View file

@ -86,7 +86,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
GLRenderManager *render = (GLRenderManager *)draw->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
shaderManagerGL_ = new ShaderManagerGLES(render);
framebufferManagerGL_ = new FramebufferManagerGLES(draw);
framebufferManagerGL_ = new FramebufferManagerGLES(draw, render);
framebufferManager_ = framebufferManagerGL_;
textureCacheGL_ = new TextureCacheGLES(draw);
textureCache_ = textureCacheGL_;
@ -163,7 +163,6 @@ GPU_GLES::GPU_GLES(GraphicsContext *gfxCtx, Draw::DrawContext *draw)
// Some of our defaults are different from hw defaults, let's assert them.
// We restore each frame anyway, but here is convenient for tests.
glstate.Restore();
drawEngine_.RestoreVAO();
textureCacheGL_->NotifyConfigChanged();
// Load shader cache.
@ -498,7 +497,6 @@ void GPU_GLES::UpdateCmdInfo() {
}
void GPU_GLES::ReapplyGfxState() {
drawEngine_.RestoreVAO();
glstate.Restore();
GPUCommon::ReapplyGfxState();
}
@ -509,7 +507,6 @@ void GPU_GLES::BeginFrame() {
textureCacheGL_->StartFrame();
drawEngine_.DecimateTrackedVertexArrays();
drawEngine_.DecimateBuffers();
depalShaderCache_.Decimate();
fragmentTestCache_.Decimate();

View file

@ -126,26 +126,32 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe
static std::string vs_code, fs_code;
vs_code = ApplyGLSLPrelude(stencil_vs, GL_VERTEX_SHADER);
fs_code = ApplyGLSLPrelude(stencil_fs, GL_FRAGMENT_SHADER);
stencilUploadProgram_ = glsl_create_source(vs_code.c_str(), fs_code.c_str(), &errorString);
std::vector<GLRShader *> shaders;
shaders.push_back(render_->CreateShader(GL_VERTEX_SHADER, vs_code));
shaders.push_back(render_->CreateShader(GL_FRAGMENT_SHADER, fs_code));
std::vector<GLRProgram::UniformLocQuery> queries;
queries.push_back({ &u_stencilUploadTex, "tex" });
std::vector<GLRProgram::Initializer> inits;
inits.push_back({ &u_stencilUploadTex, 0, 0 });
stencilUploadProgram_ = render_->CreateProgram(shaders, {}, queries, inits, false);
for (auto iter : shaders) {
render_->DeleteShader(iter);
}
if (!stencilUploadProgram_) {
ERROR_LOG_REPORT(G3D, "Failed to compile stencilUploadProgram! This shouldn't happen.\n%s", errorString.c_str());
} else {
glsl_bind(stencilUploadProgram_);
render_->BindProgram(stencilUploadProgram_);
}
GLint u_tex = glsl_uniform_loc(stencilUploadProgram_, "tex");
glUniform1i(u_tex, 0);
} else {
glsl_bind(stencilUploadProgram_);
render_->BindProgram(stencilUploadProgram_);
}
shaderManagerGL_->DirtyLastShader();
DisableState();
glstate.colorMask.set(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
render_->SetNoBlendAndMask(0x8);
glstate.stencilTest.enable();
glstate.stencilOp.set(GL_REPLACE, GL_REPLACE, GL_REPLACE);
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE);
bool useBlit = gstate_c.Supports(GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT | GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT);
@ -164,43 +170,41 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe
} else if (dstBuffer->fbo) {
draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR });
}
glViewport(0, 0, w, h);
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE);
render_->SetViewport({ 0, 0, (float)w, (float)h, 0.0f, 1.0f });
float u1 = 1.0f;
float v1 = 1.0f;
MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight, u1, v1);
textureCacheGL_->ForgetLastTexture();
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
render_->Clear(0, 0, 0, GL_STENCIL_BUFFER_BIT);
render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, 0xFF, 0xFF, 0xFF);
glstate.stencilFunc.set(GL_ALWAYS, 0xFF, 0xFF);
GLint u_stencilValue = glsl_uniform_loc(stencilUploadProgram_, "u_stencilValue");
for (int i = 1; i < values; i += i) {
if (!(usedBits & i)) {
// It's already zero, let's skip it.
continue;
}
if (dstBuffer->format == GE_FORMAT_4444) {
glstate.stencilMask.set((i << 4) | i);
glUniform1f(u_stencilValue, i * (16.0f / 255.0f));
render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, (i << 4) | i, 0xFF, 0xFF);
render_->SetUniformF1(&u_stencilValue, i * (16.0f / 255.0f));
} else if (dstBuffer->format == GE_FORMAT_5551) {
glstate.stencilMask.set(0xFF);
glUniform1f(u_stencilValue, i * (128.0f / 255.0f));
render_->SetUniformF1(&u_stencilValue, i * (128.0f / 255.0f));
} else {
glstate.stencilMask.set(i);
glUniform1f(u_stencilValue, i * (1.0f / 255.0f));
render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, i, 0xFF, 0xFF);
render_->SetUniformF1(&u_stencilValue, i * (1.0f / 255.0f));
}
DrawActiveTexture(0, 0, dstBuffer->width, dstBuffer->height, dstBuffer->bufferWidth, dstBuffer->bufferHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST);
}
glstate.stencilMask.set(0xFF);
render_->SetStencil(GL_TRUE, GL_ALWAYS, GL_KEEP, GL_KEEP, GL_KEEP, 0xFF, 0xFF, 0xFF);
if (useBlit) {
draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST);
}
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE);
RebindFramebuffer();
return true;
}

View file

@ -401,6 +401,7 @@ public:
void Use(GLRenderManager *render, DrawEngineGLES *transformDraw) {
render->BindProgram(shader_->program);
/*
// Restore will rebind all of the state below.
if (gstate_c.Supports(GPU_SUPPORTS_VAO)) {
static const GLubyte indices[4] = { 0, 1, 3, 2 };
@ -412,11 +413,12 @@ public:
}
glEnableVertexAttribArray(shader_->a_position);
glEnableVertexAttribArray(shader_->a_texcoord0);
*/
}
void Shade() {
static const GLubyte indices[4] = { 0, 1, 3, 2 };
/*
glstate.blend.force(false);
glstate.colorMask.force(true, true, true, true);
glstate.scissorTest.force(false);
@ -441,6 +443,7 @@ public:
glDisableVertexAttribArray(shader_->a_texcoord0);
glstate.Restore();
*/
}
protected:
@ -473,8 +476,7 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram
render_->BindTexture(3, clutTexture);
framebufferManagerGL_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
render_->SetTextureSampler(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_NEAREST, GL_NEAREST, 0.0f);
shaderApply.Shade();
@ -496,8 +498,6 @@ void TextureCacheGLES::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFram
framebufferManagerGL_->RebindFramebuffer();
SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight);
CHECK_GL_ERROR_IF_DEBUG();
InvalidateLastTexture();
}

View file

@ -99,16 +99,7 @@ void GLQueueRunner::RunInitSteps(const std::vector<GLRInitStep> &steps) {
break;
}
// Auto-initialize samplers.
glUseProgram(program->program);
for (int i = 0; i < 4; i++) {
char temp[256];
sprintf(temp, "Sampler%i", i);
int samplerLoc = glGetUniformLocation(program->program, temp);
if (samplerLoc != -1) {
glUniform1i(samplerLoc, i);
}
}
// Query all the uniforms.
for (int i = 0; i < program->queries_.size(); i++) {

View file

@ -318,6 +318,8 @@ private:
GLuint globalVAO_;
GLint curFramebuffer_ = 0;
int curFBWidth_;
int curFBHeight_;
// Readback buffer. Currently we only support synchronous readback, so we only really need one.
// We size it generously.

View file

@ -122,7 +122,7 @@ public:
glDeleteBuffers(1, &buffer);
}
}
GLuint buffer;
GLuint buffer = 0;
GLuint target_;
private:
};
@ -216,6 +216,8 @@ public:
return step.create_framebuffer.framebuffer;
}
// Can't replace uniform initializers with direct calls to SetUniform() etc because there might
// not be an active render pass.
GLRProgram *CreateProgram(
std::vector<GLRShader *> shaders, std::vector<GLRProgram::Semantic> semantics, std::vector<GLRProgram::UniformLocQuery> queries,
std::vector<GLRProgram::Initializer> initalizers, bool supportDualSource) {
@ -398,6 +400,15 @@ public:
curRenderStep_->commands.push_back(data);
}
void SetUniformF1(GLint *loc, const float udata) {
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData data{ GLRRenderCommand::UNIFORM4F };
data.uniform4.loc = loc;
data.uniform4.count = 1;
memcpy(data.uniform4.v, &udata, sizeof(float));
curRenderStep_->commands.push_back(data);
}
void SetUniformF(const char *name, int count, const float *udata) {
_dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER);
GLRRenderData data{ GLRRenderCommand::UNIFORM4F };