From d6e7ea4a4ed9deb196e5d101e1e8226e39f86113 Mon Sep 17 00:00:00 2001 From: "gregory.hainaut" Date: Mon, 5 Mar 2012 20:16:26 +0000 Subject: [PATCH] GSdx-ogl: LINUX only * request a minimum of 1 for texture dimension * Use offscreen texture likes DX11. * add more bits for extra texture format * do operation on texture unit 0 to avoid ping-pong between unit 0/2 git-svn-id: http://pcsx2.googlecode.com/svn/branches/gsdx-ogl@5114 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/GSdx/GSDeviceOGL.cpp | 49 +++++-------- plugins/GSdx/GSLinuxDialog.cpp | 25 +++++-- plugins/GSdx/GSTextureCacheOGL.cpp | 2 +- plugins/GSdx/GSTextureOGL.cpp | 111 +++++++++++++++++++---------- plugins/GSdx/GSTextureOGL.h | 3 +- 5 files changed, 116 insertions(+), 74 deletions(-) diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index 63a5078d41..40ecf105ca 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -21,6 +21,10 @@ #include "GSDeviceOGL.h" +// TODO performance cost to investigate +// Texture attachment/glDrawBuffer. For the moment it set every draw and potentially multiple time (first time in clear, second time in rendering) +// Attachment 1 is only used with the GL_16UI format + //#define LOUD_DEBUGGING //#define PRINT_FRAME_NUMBER //#define ONLY_LINES @@ -507,7 +511,7 @@ void GSDeviceOGL::DebugInput() m_state.ps_srv[i]->Save(format("/tmp/in_f%d__d%d__%d.bmp", g_frame_count, g_draw_count, i)); } } - //if (m_state.rtv != NULL) m_state.rtv->Save(format("/tmp/in_current_out_%d.bmp", g_draw_count)); + //if (m_state.rtv != NULL) m_state.rtv->Save(format("/tmp/target_f%d__d%d__tex.bmp", g_frame_count, g_draw_count)); //if (m_state.dsv != NULL) m_state.dsv->Save(format("/tmp/ds_in_%d.bmp", g_draw_count)); fprintf(stderr, "Draw %d (Frame %d)\n", g_draw_count, g_frame_count); @@ -520,6 +524,8 @@ void GSDeviceOGL::DebugInput() void GSDeviceOGL::DebugOutput() { + CheckDebugLog(); + bool dump_me = false; uint32 start = theApp.GetConfig("debug_ogl_dump", 0); uint32 length = theApp.GetConfig("debug_ogl_dump_length", 5); @@ -536,7 +542,6 @@ void GSDeviceOGL::DebugOutput() fprintf(stderr, "\n"); } - CheckDebugLog(); } void GSDeviceOGL::DrawPrimitive() @@ -596,12 +601,7 @@ void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c) // FIXME1 I need to clarify this FBO attachment stuff // I would like to avoid FBO for a basic clean operation OMSetFBO(m_fbo); - // FIXME2: - // it would be better to attach the texture to another slot (like 3) - // but it crash for an unknow reason - // The following error appears "glClearBufferfv failed because the currently set GL_DRAW_FRAMEBUFFER binding has incomplete status" - // Maybe glDrawBuffer must be updated but it does not solve the crash... - // FIXME3: I still have another crash on GOW... + glDrawBuffer(GL_COLOR_ATTACHMENT0); static_cast(t)->Attach(GL_COLOR_ATTACHMENT0); glClearBufferfv(GL_COLOR, 0, c.v); } @@ -673,8 +673,8 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w return false; } - // FIXME: I used directly an offscreen texture because they are the same on Opengl - //if(GSTexture* rt = CreateRenderTarget(w, h, false, format)) + // FIXME: It is possible to bypass completely offscreen-buffer on opengl but it needs some re-thinking of the code. + // For the moment mimic dx11 GSTexture* rt = CreateRenderTarget(w, h, false, format); if(rt) { @@ -687,9 +687,12 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w if(src2 != src) Recycle(src2); } -#if 0 + + GSVector4i dor(0, 0, w, h); dst = CreateOffscreen(w, h, format); + if (dst) CopyRect(rt, dst, dor); +#if 0 if(dst) { m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt); @@ -699,8 +702,8 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w Recycle(rt); } - //return dst; - return rt; + return dst; + //return rt; } // Copy a sub part of a texture into another @@ -724,27 +727,11 @@ void GSDeviceOGL::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r) // uint srcName, enum srcTarget, int srcLevel, int srcX, int srcY, int srcZ, // uint dstName, enum dstTarget, int dstLevel, int dstX, int dstY, int dstZ, // sizei width, sizei height, sizei depth); - glCopyImageSubDataNV( static_cast(st)->GetID(), GL_TEXTURE_2D, + glCopyImageSubDataNV( static_cast(st)->GetID(), static_cast(st)->GetTarget(), 0, r.x, r.y, 0, - static_cast(dt)->GetID(), GL_TEXTURE_2D, + static_cast(dt)->GetID(), static_cast(dt)->GetTarget(), 0, r.x, r.y, 0, r.width(), r.height(), 1); -#if 0 - - // FIXME FBO - GLuint fbo_old = m_state.fbo; - OMSetFBO(m_fbo); - - // Set the input of glCopyTexSubImage2D - static_cast(st)->Attach(GL_COLOR_ATTACHMENT1); - glReadBuffer(GL_COLOR_ATTACHMENT1); - - // Copy the full image - static_cast(dt)->EnableUnit(0); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, dt->GetWidth(), dt->GetHeight()); - - OMSetFBO(fbo_old); -#endif #if 0 D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; diff --git a/plugins/GSdx/GSLinuxDialog.cpp b/plugins/GSdx/GSLinuxDialog.cpp index 4a0ccd57ab..255e3a55e6 100644 --- a/plugins/GSdx/GSLinuxDialog.cpp +++ b/plugins/GSdx/GSLinuxDialog.cpp @@ -62,10 +62,27 @@ GtkWidget* CreateRenderComboBox() if(!s.note.empty()) label += format(" (%s)", s.note.c_str()); - // (dev only) for any NULL stuff - if (i >= 7 && i <= 9) label += " (debug only)"; - // (experimental) for opengl stuff - if (i == 10 || i == 11) label += " (experimental)"; + // Add some tags to ease users selection + switch (i) { + // better use opengl instead of SDL + case 6: + label += " (deprecated)"; + break; + + // (dev only) for any NULL stuff + case 7: + case 8: + case 9: + label += " (debug only)"; + break; + + // opengl harware is not yet finished + case 10: + label += " (experimental)"; + break; + default: + break; + } gtk_combo_box_append_text(GTK_COMBO_BOX(render_combo_box), label.c_str()); } diff --git a/plugins/GSdx/GSTextureCacheOGL.cpp b/plugins/GSdx/GSTextureCacheOGL.cpp index 74eba438a0..98023ae518 100644 --- a/plugins/GSdx/GSTextureCacheOGL.cpp +++ b/plugins/GSdx/GSTextureCacheOGL.cpp @@ -96,7 +96,7 @@ void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r) offscreen->Unmap(); } - //m_renderer->m_dev->Recycle(offscreen); + m_renderer->m_dev->Recycle(offscreen); } } diff --git a/plugins/GSdx/GSTextureOGL.cpp b/plugins/GSdx/GSTextureOGL.cpp index 2590bbc3be..00f4cffd37 100644 --- a/plugins/GSdx/GSTextureOGL.cpp +++ b/plugins/GSdx/GSTextureOGL.cpp @@ -26,7 +26,7 @@ static int g_state_texture_unit = -1; static int g_state_texture_id = -1; GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint fbo_read) - : m_extra_buffer_id(0), + : m_pbo_id(0), m_pbo_size(0) { // ************************************************************* @@ -48,8 +48,11 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint // glBlitFramebuffer // ************************************************************* - m_size.x = w; - m_size.y = h; + // m_size.x = w; + // m_size.y = h; + // FIXME + m_size.x = max(1,w); + m_size.y = max(1,h); m_format = format; m_type = type; m_msaa = msaa; @@ -80,7 +83,7 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint break; } // Extra buffer to handle various pixel transfer - glGenBuffers(1, &m_extra_buffer_id); + glGenBuffers(1, &m_pbo_id); uint msaa_level; if (m_msaa) { @@ -93,16 +96,30 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint // Allocate the buffer switch (m_type) { case GSTexture::DepthStencil: - EnableUnit(2); + EnableUnit(0); glTexImage2D(m_texture_target, 0, m_format, m_size.x, m_size.y, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL); break; + + case GSTexture::Offscreen: + // Allocate a pbo with the texture + if (m_format == GL_RGBA8) m_pbo_size = m_size.x * m_size.y * 4; + else if (m_format == GL_R16UI) m_pbo_size = m_size.x * m_size.y * 2; + else { + fprintf(stderr, "wrong texture pixel format :%x\n", m_format); + assert(0); // TODO Later + } + + glBindBuffer(GL_PIXEL_PACK_BUFFER, m_pbo_id); + glBufferData(GL_PIXEL_PACK_BUFFER, m_pbo_size, NULL, GL_STREAM_DRAW); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + case GSTexture::RenderTarget: case GSTexture::Texture: // FIXME // Howto allocate the texture unit !!! // In worst case the HW renderer seems to use 3 texture unit // For the moment SW renderer only use 1 so don't bother - EnableUnit(2); + EnableUnit(0); if (m_format == GL_RGBA8) glTexImage2D(m_texture_target, 0, m_format, m_size.x, m_size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); else if (m_format == GL_R16UI) @@ -114,22 +131,13 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint assert(0); // TODO Later } break; - case GSTexture::Offscreen: - if (m_type == GL_RGBA8) m_pbo_size = m_size.x * m_size.y * 4; - else if (m_type == GL_R16UI) m_pbo_size = m_size.x * m_size.y * 2; - else assert(0); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_extra_buffer_id); - glBufferData(GL_PIXEL_PACK_BUFFER, m_pbo_size, NULL, GL_STREAM_DRAW); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - break; default: break; } } GSTextureOGL::~GSTextureOGL() { - glDeleteBuffers(1, &m_extra_buffer_id); + glDeleteBuffers(1, &m_pbo_id); glDeleteTextures(1, &m_texture_id); } @@ -148,7 +156,7 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch) // FIXME warning order of the y axis // FIXME I'm not confident with GL_UNSIGNED_BYTE type - EnableUnit(2); + EnableUnit(0); // pitch could be different of width*element_size glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch>>2); @@ -224,29 +232,41 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* r) // glMapBuffer — map a buffer object's data store // Can be used on GL_PIXEL_UNPACK_BUFFER or GL_TEXTURE_BUFFER if (m_type == GSTexture::Offscreen) { - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_extra_buffer_id); - // FIXME It might be possible to only map a subrange of the texture based on r object + // Bind the texture to the read framebuffer to avoid any disturbance + EnableUnit(0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_target, m_texture_id, 0); + glReadBuffer(GL_COLOR_ATTACHMENT0); - // Load the PBO - if (m_format == GL_RGBA8) + // FIXME It might be possible to only read a subrange of the texture based on r object + // Load the PBO with the data + glBindBuffer(GL_PIXEL_PACK_BUFFER, m_pbo_id); + if (m_format == GL_RGBA8) { + glPixelStorei(GL_PACK_ALIGNMENT, 4); glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, 0); - else if (m_format == GL_R16UI) + } else if (m_format == GL_R16UI) { + glPixelStorei(GL_PACK_ALIGNMENT, 2); glReadPixels(0, 0, m_size.x, m_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, 0); - else if (m_format == GL_R8) + } else if (m_format == GL_R8) { + glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_BYTE, 0); - else { + } else { fprintf(stderr, "wrong texture pixel format :%x\n", m_format); assert(0); } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); // Give access from the CPU - uint32 map_flags = GL_MAP_READ_BIT; - m.bits = (uint8*) glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pbo_size, map_flags); + m.bits = (uint8*) glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pbo_size, GL_MAP_READ_BIT); m.pitch = m_size.x; - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - - return true; + if ( m.bits ) { + return true; + } else { + fprintf(stderr, "bad mapping of the pbo\n"); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + return false; + } } return false; @@ -272,6 +292,8 @@ void GSTextureOGL::Unmap() { if (m_type == GSTexture::Offscreen) { glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + } } @@ -377,30 +399,45 @@ bool GSTextureOGL::Save(const string& fn, bool dds) uint32 pitch = 4 * m_size.x; if (IsDss()) pitch *= 2; char* image = (char*)malloc(pitch * m_size.y); + bool status = true; // FIXME instead of swapping manually B and R maybe you can request the driver to do it // for us if (IsBackbuffer()) { - glReadBuffer(GL_BACK); + //glReadBuffer(GL_BACK); + //glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image); } else if(IsDss()) { - EnableUnit(2); + EnableUnit(0); glGetTexImage(m_texture_target, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, image); } else { glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); - EnableUnit(2); - glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, m_texture_target, m_texture_id, 0); + EnableUnit(0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_target, m_texture_id, 0); - glReadBuffer(GL_COLOR_ATTACHMENT1); - glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image); + glReadBuffer(GL_COLOR_ATTACHMENT0); + if (m_format == GL_RGBA8) + glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image); + else if (m_format == GL_R16UI) + { + glReadPixels(0, 0, m_size.x, m_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, image); + // Not supported in Save function + status = false; + } + else if (m_format == GL_R8) + { + glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_BYTE, image); + // Not supported in Save function + status = false; + } glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } - Save(fn, image, pitch); + if (status) Save(fn, image, pitch); free(image); - return true; + return status; } diff --git a/plugins/GSdx/GSTextureOGL.h b/plugins/GSdx/GSTextureOGL.h index 657d922435..017431a128 100644 --- a/plugins/GSdx/GSTextureOGL.h +++ b/plugins/GSdx/GSTextureOGL.h @@ -28,7 +28,7 @@ class GSTextureOGL : public GSTexture private: GLenum m_texture_target; // texture target: 2D, rectangle etc... GLuint m_texture_id; // the texture id - uint m_extra_buffer_id; + uint m_pbo_id; int m_pbo_size; GLuint m_fbo_read; @@ -49,4 +49,5 @@ class GSTextureOGL : public GSTexture bool IsDss() { return (m_type == GSTexture::DepthStencil); } GLuint GetID() { return m_texture_id; } + GLenum GetTarget() { return m_texture_target; } };