From 2f4e2d8b6b3e11fe03b2257d660a948800dc7537 Mon Sep 17 00:00:00 2001 From: "gregory.hainaut" Date: Sat, 31 Dec 2011 14:38:58 +0000 Subject: [PATCH] GSdx-ogl: happy new years commit :) * move all vertex buffer stuff into the class * Bypass FIFO2 because of multithread issue with OGL(temporary workaround until we found a nicer solutions) git-svn-id: http://pcsx2.googlecode.com/svn/branches/gsdx-ogl@5035 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/GSdx/GS.cpp | 17 +++++ plugins/GSdx/GSDeviceOGL.cpp | 39 ++--------- plugins/GSdx/GSDeviceOGL.h | 113 +++++++++++++++++++++----------- plugins/GSdx/GSTextureFXOGL.cpp | 4 +- plugins/GSdx/GSTextureOGL.cpp | 14 +++- 5 files changed, 111 insertions(+), 76 deletions(-) diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index 6daa508c0..7badb94b8 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -396,11 +396,28 @@ EXPORT_C GSwriteCSR(uint32 csr) EXPORT_C GSreadFIFO(uint8* mem) { +#ifdef _LINUX + // FIXME: double check which thread call this function + // See fifo2 issue below + if (theApp.GetConfig("renderer", 0) == 12) { + fprintf(stderr, "Disable FIFO1 on opengl\n"); + } +#endif s_gs->ReadFIFO(mem, 1); } EXPORT_C GSreadFIFO2(uint8* mem, uint32 size) { +#ifdef _LINUX + // FIXME called from EE core thread not MTGS which cause + // invalidate data for opengl + if (theApp.GetConfig("renderer", 0) == 12) { +#ifdef OGL_DEBUG + fprintf(stderr, "Disable FIFO2 on opengl\n"); +#endif + return; + } +#endif s_gs->ReadFIFO(mem, size); } diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index bb766c7a5..a9d794bc5 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -226,12 +226,12 @@ bool GSDeviceOGL::Create(GSWnd* wnd) // **************************************************************** // Vertex buffer state // **************************************************************** - GSInputLayout il_convert[2] = + GSInputLayoutOGL il_convert[2] = { {0, 4, GL_FLOAT, GL_FALSE, sizeof(GSVertexPT1), (const GLvoid*)offsetof(struct GSVertexPT1, p) }, {1, 2, GL_FLOAT, GL_FALSE, sizeof(GSVertexPT1), (const GLvoid*)offsetof(struct GSVertexPT1, t) }, }; - m_vb_sr = new GSVertexBufferState(sizeof(GSVertexPT1), il_convert, countof(il_convert)); + m_vb_sr = new GSVertexBufferStateOGL(sizeof(GSVertexPT1), il_convert, countof(il_convert)); // **************************************************************** // convert @@ -546,7 +546,7 @@ void GSDeviceOGL::DrawPrimitive() } #endif - glDrawArrays(m_state.topology, m_state.vb_state->start, m_state.vb_state->count); + m_state.vb_state->draw_arrays(m_state.topology); // DUMP OUTPUT #ifdef DUMP_START @@ -964,8 +964,7 @@ GSTexture* GSDeviceOGL::Resolve(GSTexture* t) void GSDeviceOGL::EndScene() { - m_state.vb_state->start += m_state.vb_state->count; - m_state.vb_state->count = 0; + m_state.vb_state->draw_done(); } void GSDeviceOGL::SetUniformBuffer(GSUniformBufferOGL* cb) @@ -976,7 +975,7 @@ void GSDeviceOGL::SetUniformBuffer(GSUniformBufferOGL* cb) } } -void GSDeviceOGL::IASetVertexState(GSVertexBufferState* vb_state) +void GSDeviceOGL::IASetVertexState(GSVertexBufferStateOGL* vb_state) { if (m_state.vb_state != vb_state) { m_state.vb_state = vb_state; @@ -986,33 +985,7 @@ void GSDeviceOGL::IASetVertexState(GSVertexBufferState* vb_state) void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t count) { - // Note: For an explanation of the map flag - // see http://www.opengl.org/wiki/Buffer_Object_Streaming - uint32 map_flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; - - GSVertexBufferState* vb = m_state.vb_state; - vb->count = count; - - // Current GPU buffer is really too small need to realocate a new one - if (count > vb->limit) { - vb->allocate(std::max(count * 3 / 2, 60000)); - - } else if (count > (vb->limit - vb->start) ) { - // Not enough left free room. Just go back at the beginning - vb->start = 0; - - // Tell the driver that it can orphan previous buffer and restart from a scratch buffer. - // Technically the buffer will not be accessible by the application anymore but the - // GL will effectively remove it when draws call are finised. - map_flags |= GL_MAP_INVALIDATE_BUFFER_BIT; - } else { - // Tell the driver that it doesn't need to contain any valid buffer data, and that you promise to write the entire range you map - map_flags |= GL_MAP_INVALIDATE_RANGE_BIT; - } - - vb->upload(vertices, map_flags); - // FIXME: disable it when code is working - CheckDebugLog(); + m_state.vb_state->upload(vertices, count); } void GSDeviceOGL::IASetPrimitiveTopology(GLenum topology) diff --git a/plugins/GSdx/GSDeviceOGL.h b/plugins/GSdx/GSDeviceOGL.h index 016353a8b..9100d1c5d 100644 --- a/plugins/GSdx/GSDeviceOGL.h +++ b/plugins/GSdx/GSDeviceOGL.h @@ -128,7 +128,7 @@ public: } }; -struct GSInputLayout { +struct GSInputLayoutOGL { GLuint index; GLint size; GLenum type; @@ -137,51 +137,73 @@ struct GSInputLayout { const GLvoid* offset; }; -struct GSVertexBufferState { - size_t stride; - size_t start; - size_t count; - size_t limit; - GLuint vb; - GLuint va; - - GSVertexBufferState(size_t stride, GSInputLayout* layout, uint32 layout_nbr) : stride(stride) - , count(0) - { - glGenBuffers(1, &vb); - glGenVertexArrays(1, &va); - bind(); - allocate(60000); // Opengl works best with 1-4MB buffer. 60k element seems a good value. - set_internal_format(layout, layout_nbr); - } +class GSVertexBufferStateOGL { + size_t m_stride; + size_t m_start; + size_t m_count; + size_t m_limit; + GLuint m_vb; + GLuint m_va; + const GLenum m_target; void allocate(size_t new_limit) { - start = 0; - limit = new_limit; - glBufferData(GL_ARRAY_BUFFER, limit * stride, NULL, GL_STREAM_DRAW); + m_start = 0; + m_limit = new_limit; + glBufferData(m_target, m_limit * m_stride, NULL, GL_STREAM_DRAW); + } + +public: + GSVertexBufferStateOGL(size_t stride, GSInputLayoutOGL* layout, uint32 layout_nbr) + : m_stride(stride) + , m_count(0) + , m_target(GL_ARRAY_BUFFER) + { + glGenBuffers(1, &m_vb); + glGenVertexArrays(1, &m_va); + bind(); + allocate(60000); // Opengl works best with 1-4MB buffer. 60k element seems a good value. Note stride is 32 + set_internal_format(layout, layout_nbr); } void bind() { - glBindVertexArray(va); - glBindBuffer(GL_ARRAY_BUFFER, vb); + glBindVertexArray(m_va); + glBindBuffer(m_target, m_vb); } - void upload(const void* src, uint32 flags) + void upload(const void* src, uint32 count) { - uint8* dst = (uint8*) glMapBufferRange(GL_ARRAY_BUFFER, stride*start, stride*count, flags); -#ifdef OGL_DEBUG - if (dst == NULL) { - fprintf(stderr, "CRITICAL ERROR map failed for vb !!!\n"); - return; + m_count = count; + + // Note: For an explanation of the map flag + // see http://www.opengl.org/wiki/Buffer_Object_Streaming + uint32 map_flags = GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT; + + // Current GPU buffer is really too small need to allocate a new one + if (m_count > m_limit) { + allocate(std::max(count * 3 / 2, 60000)); + + } else if (m_count > (m_limit - m_start) ) { + // Not enough left free room. Just go back at the beginning + m_start = 0; + + // Tell the driver that it can orphan previous buffer and restart from a scratch buffer. + // Technically the buffer will not be accessible by the application anymore but the + // GL will effectively remove it when draws call are finised. + map_flags |= GL_MAP_INVALIDATE_BUFFER_BIT; + } else { + // Tell the driver that it doesn't need to contain any valid buffer data, and that you promise to write the entire range you map + map_flags |= GL_MAP_INVALIDATE_RANGE_BIT; } -#endif - memcpy(dst, src, stride*count); - glUnmapBuffer(GL_ARRAY_BUFFER); + + // Upload the data to the buffer + uint8* dst = (uint8*) glMapBufferRange(m_target, m_stride*m_start, m_stride*m_count, map_flags); + memcpy(dst, src, m_stride*m_count); + glUnmapBuffer(m_target); } - void set_internal_format(GSInputLayout* layout, uint32 layout_nbr) + void set_internal_format(GSInputLayoutOGL* layout, uint32 layout_nbr) { for (int i = 0; i < layout_nbr; i++) { // Note this function need both a vertex array object and a GL_ARRAY_BUFFER buffer @@ -199,10 +221,21 @@ struct GSVertexBufferState { } } - ~GSVertexBufferState() + void draw_arrays(GLenum topology) { - glDeleteBuffers(1, &vb); - glDeleteVertexArrays(1, &va); + glDrawArrays(topology, m_start, m_count); + } + + void draw_done() + { + m_start += m_count; + m_count = 0; + } + + ~GSVertexBufferStateOGL() + { + glDeleteBuffers(1, &m_vb); + glDeleteVertexArrays(1, &m_va); } }; @@ -451,8 +484,8 @@ class GSDeviceOGL : public GSDevice GLuint m_pipeline; // pipeline to attach program shader GLuint m_fbo; // frame buffer container - GSVertexBufferState* m_vb; // vb_state for HW renderer - GSVertexBufferState* m_vb_sr; // vb_state for StretchRect + GSVertexBufferStateOGL* m_vb; // vb_state for HW renderer + GSVertexBufferStateOGL* m_vb_sr; // vb_state for StretchRect struct { GLuint ps[2]; // program object @@ -488,7 +521,7 @@ class GSDeviceOGL : public GSDevice struct { - GSVertexBufferState* vb_state; + GSVertexBufferStateOGL* vb_state; GLenum topology; // (ie GL_TRIANGLES...) GLuint vs; // program GSUniformBufferOGL* cb; // uniform current buffer @@ -604,7 +637,7 @@ class GSDeviceOGL : public GSDevice void IASetPrimitiveTopology(GLenum topology); void IASetVertexBuffer(const void* vertices, size_t count); - void IASetVertexState(GSVertexBufferState* vb_state); + void IASetVertexState(GSVertexBufferStateOGL* vb_state); void SetUniformBuffer(GSUniformBufferOGL* cb); diff --git a/plugins/GSdx/GSTextureFXOGL.cpp b/plugins/GSdx/GSTextureFXOGL.cpp index 9560cb5b9..f3f37466d 100644 --- a/plugins/GSdx/GSTextureFXOGL.cpp +++ b/plugins/GSdx/GSTextureFXOGL.cpp @@ -61,7 +61,7 @@ void GSDeviceOGL::CreateTextureFX() //float4 c : COLOR0; //float4 f : COLOR1; - GSInputLayout vert_format[6] = + GSInputLayoutOGL vert_format[6] = { // FIXME {0 , 2 , GL_FLOAT , GL_FALSE , sizeof(GSVertexHW11) , (const GLvoid*)(0) } , @@ -72,7 +72,7 @@ void GSDeviceOGL::CreateTextureFX() // note: there is a 32 bits pad {5 , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof(GSVertexHW11) , (const GLvoid*)(28) } , }; - m_vb = new GSVertexBufferState(sizeof(GSVertexHW11), vert_format, countof(vert_format)); + m_vb = new GSVertexBufferStateOGL(sizeof(GSVertexHW11), vert_format, countof(vert_format)); } void GSDeviceOGL::SetupIA(const void* vertices, int count, GLenum prim) diff --git a/plugins/GSdx/GSTextureOGL.cpp b/plugins/GSdx/GSTextureOGL.cpp index 39c42a25e..b4d1f3840 100644 --- a/plugins/GSdx/GSTextureOGL.cpp +++ b/plugins/GSdx/GSTextureOGL.cpp @@ -175,8 +175,20 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch) // pitch could be different of width*element_size glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch>>2); // FIXME : it crash on colin mcrae rally 3 (others game too) when the size is 16 - //if (m_size.x != 16) + //fprintf(stderr, "Texture %dx%d with a pitch of %d\n", m_size.x, m_size.y, pitch >>2); + //fprintf(stderr, "Box (%d,%d)x(%d,%d)\n", r.x, r.y, r.width(), r.height()); + glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, data); +#if 0 + //if (m_size.x != 16) + if (r.width() > 16 && r.height() > 16) + glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, data); + else { + fprintf(stderr, "skip texture upload\n"); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Restore default behavior + return false; + } +#endif glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // Restore default behavior