From 33a9ac370ac47a9103e693eadd6fe4459fdf66d8 Mon Sep 17 00:00:00 2001 From: "gregory.hainaut" Date: Fri, 23 Dec 2011 12:32:40 +0000 Subject: [PATCH] gsdx-ogl: LINUX-ONLY * implement offscreen and cache (mostly a copy past of dx) * add the missing macro selector of the shader... git-svn-id: http://pcsx2.googlecode.com/svn/branches/gsdx-ogl@5009 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/GSdx/GSDeviceOGL.cpp | 61 +++++++++++++----------- plugins/GSdx/GSTextureCacheOGL.cpp | 10 ++-- plugins/GSdx/GSTextureOGL.cpp | 75 +++++++++++++++++++----------- plugins/GSdx/GSTextureOGL.h | 2 +- 4 files changed, 87 insertions(+), 61 deletions(-) diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index fd47ee0b5f..7b3a74fd7f 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -526,12 +526,22 @@ void GSDeviceOGL::ClearRenderTarget(GSTexture* t, uint32 c) void GSDeviceOGL::ClearDepth(GSTexture* t, float c) { + // FIXME I need to clarify this FBO attachment stuff + // I would like to avoid FBO for a basic clean operation + OMSetFBO(m_fbo); + static_cast(t)->Attach(GL_DEPTH_STENCIL_ATTACHMENT); + // FIXME can you clean depth and stencil separately glClearBufferfv(GL_DEPTH, 0, &c); } void GSDeviceOGL::ClearStencil(GSTexture* t, uint8 c) { + // FIXME I need to clarify this FBO attachment stuff + // I would like to avoid FBO for a basic clean operation + OMSetFBO(m_fbo); + static_cast(t)->Attach(GL_DEPTH_STENCIL_ATTACHMENT); GLint color = c; + // FIXME can you clean depth and stencil separately glClearBufferiv(GL_STENCIL, 0, &color); } @@ -558,56 +568,45 @@ GSTexture* GSDeviceOGL::CreateOffscreen(int w, int h, int format) // blit a texture into an offscreen buffer GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format) { - // I'm not sure about the object type for offscreen buffer - // TODO later; - - assert(0); - - // Need to find format equivalent. Then I think it will be straight forward - - // A four-component, 32-bit unsigned-normalized-integer format that supports 8 bits per channel including alpha. - // DXGI_FORMAT_R8G8B8A8_UNORM <=> GL_RGBA8 - - // A single-component, 16-bit unsigned-integer format that supports 16 bits for the red channel - // DXGI_FORMAT_R16_UINT <=> GL_R16 -#if 0 GSTexture* dst = NULL; - if(format == 0) - { - format = DXGI_FORMAT_R8G8B8A8_UNORM; - } + if(format == 0) format = GL_RGBA8; - if(format != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT) + if(format != GL_RGBA8 && format != GL_R16UI) { ASSERT(0); return false; } - if(GSTexture* rt = CreateRenderTarget(w, h, false, format)) + // FIXME: I used directly an offscreen texture because they are the same on Opengl + //if(GSTexture* rt = CreateRenderTarget(w, h, false, format)) + GSTexture* rt = CreateRenderTarget(w, h, false, format); + if(rt) { GSVector4 dr(0, 0, w, h); if(GSTexture* src2 = src->IsMSAA() ? Resolve(src) : src) { - StretchRect(src2, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL); + StretchRect(src2, sr, rt, dr, m_convert.ps[format == GL_R16UI ? 1 : 0]); if(src2 != src) Recycle(src2); } +#if 0 dst = CreateOffscreen(w, h, format); if(dst) { m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt); } +#endif Recycle(rt); } - return dst; -#endif + //return dst; + return rt; } // Copy a sub part of a texture into another @@ -622,12 +621,19 @@ void GSDeviceOGL::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r) return; } - // This function is useless on opengl. The only call I found copy the whole texture data to another one - assert(0); - // GL_NV_copy_image seem like the good extension but not supported on AMD... // Maybe opengl 4.3 ! + // FIXME check those function work as expected + // 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()); + +#if 0 // FIXME attach the texture to the FBO GSTextureOGL* st_ogl = (GSTextureOGL*) st; GSTextureOGL* dt_ogl = (GSTextureOGL*) dt; @@ -643,6 +649,7 @@ void GSDeviceOGL::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r) //glCopyTexSubImage2D(dt_ogl.m_texture_target, 0, 0, 0, r.left, r.bottom, r.right-r.left, r.top-r.bottom); // FIXME I'm not sure GL_TEXTURE_RECTANGLE is supported!!! //glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE, 0, 0, 0, r.left, r.bottom, r.right-r.left, r.top-r.bottom); +#endif #if 0 D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; m_ctx->CopySubresourceRegion(*(GSTexture11*)dt, 0, 0, 0, 0, *(GSTexture11*)st, 0, &box); @@ -819,7 +826,7 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* ver // gs - GSSetShader(NULL); + GSSetShader(0); // ps @@ -1153,7 +1160,7 @@ void GSDeviceOGL::CompileShaderFromSource(const std::string& glsl_file, const st // Select the entry point ie the main function std::string entry_main = format("#define %s main\n", entry.c_str()); - std::string header = version + shader_type + entry_main; + std::string header = version + shader_type + entry_main + macro_sel; // ***************************************************** // Read the source file diff --git a/plugins/GSdx/GSTextureCacheOGL.cpp b/plugins/GSdx/GSTextureCacheOGL.cpp index 5b4605a2c3..b248d1dcf1 100644 --- a/plugins/GSdx/GSTextureCacheOGL.cpp +++ b/plugins/GSdx/GSTextureCacheOGL.cpp @@ -30,11 +30,9 @@ GSTextureCacheOGL::GSTextureCacheOGL(GSRenderer* r) void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r) { - // Except format (CopyOffscreen method), everything else seem portable -#if 0 if(t->m_type != RenderTarget) { - // TODO + assert(0); return; } @@ -63,7 +61,10 @@ void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r) GSVector4 src = GSVector4(r) * GSVector4(t->m_texture->GetScale()).xyxy() / GSVector4(t->m_texture->GetSize()).xyxy(); + GLuint format = TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S ? GL_R16UI : GL_RGBA8; +#if 0 DXGI_FORMAT format = TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; +#endif if(GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(t->m_texture, src, w, h, format)) { @@ -94,8 +95,7 @@ void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r) offscreen->Unmap(); } - m_renderer->m_dev->Recycle(offscreen); + //m_renderer->m_dev->Recycle(offscreen); } -#endif } diff --git a/plugins/GSdx/GSTextureOGL.cpp b/plugins/GSdx/GSTextureOGL.cpp index f38c6ad7f7..bf52cb4bfb 100644 --- a/plugins/GSdx/GSTextureOGL.cpp +++ b/plugins/GSdx/GSTextureOGL.cpp @@ -28,7 +28,7 @@ static uint g_state_texture_id = 0; GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format) : m_texture_unit(0), m_extra_buffer_id(0), - m_extra_buffer_allocated(false) + m_pbo_size(0) { // ************************************************************* // Opengl world @@ -83,6 +83,16 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format) // Generate the buffer switch (m_type) { + case GSTexture::Offscreen: + //FIXME I not sure we need a pixel buffer object. It seems more a texture + // glGenBuffers(1, &m_texture_id); + // m_texture_target = GL_PIXEL_UNPACK_BUFFER; + // assert(0); + // Note there is also a buffer texture!!! + // http://www.opengl.org/wiki/Buffer_Texture + // Note: in this case it must use in GLSL + // gvec texelFetch(gsampler sampler, ivec texCoord, int lod[, int sample]); + // corollary we can maybe use it for multisample stuff case GSTexture::Texture: case GSTexture::RenderTarget: glGenTextures(1, &m_texture_id); @@ -92,16 +102,6 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format) glGenRenderbuffers(1, &m_texture_id); m_texture_target = GL_RENDERBUFFER; break; - case GSTexture::Offscreen: - //FIXME I not sure we need a pixel buffer object. It seems more a texture - // glGenBuffers(1, &m_texture_id); - // m_texture_target = GL_PIXEL_UNPACK_BUFFER; - assert(0); - // Note there is also a buffer texture!!! - // http://www.opengl.org/wiki/Buffer_Texture - // Note: in this case it must use in GLSL - // gvec texelFetch(gsampler sampler, ivec texCoord, int lod[, int sample]); - // corollary we can maybe use it for multisample stuff break; case GSTexture::Backbuffer: m_texture_target = 0; @@ -140,7 +140,12 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format) assert(0); // TODO Later break; case GSTexture::Offscreen: - assert(0); + 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); break; default: break; } @@ -197,19 +202,18 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch) // The case appears on SW mode. Src pitch is 2x dst pitch. int rowbytes = r.width() << 2; if (pitch != rowbytes) { - uint32 pbo_size = m_size.x * m_size.y * 4; uint32 map_flags = GL_MAP_WRITE_BIT; glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_extra_buffer_id); - if (!m_extra_buffer_allocated) { - glBufferData(GL_PIXEL_UNPACK_BUFFER, pbo_size, NULL, GL_STREAM_DRAW); - m_extra_buffer_allocated = true; + if (!m_pbo_size) { + m_pbo_size = m_size.x * m_size.y * 4; + glBufferData(GL_PIXEL_UNPACK_BUFFER, m_pbo_size, NULL, GL_STREAM_DRAW); } else { GL_MAP_INVALIDATE_BUFFER_BIT; } uint8* src = (uint8*) data; - uint8* dst = (uint8*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, pbo_size, map_flags); + uint8* dst = (uint8*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, m_pbo_size, map_flags); for(int h = r.height(); h > 0; h--, src += pitch, dst += rowbytes) { memcpy(dst, src, rowbytes); @@ -274,6 +278,26 @@ 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 + + // Load the PBO + if (m_format == GL_R16UI) + glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_SHORT, 0); + else if (m_format == GL_RGBA8) + glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, 0); + else + assert(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.pitch = m_size.x; + + return true; + } + return false; #if 0 if(r != NULL) @@ -302,14 +326,9 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* r) void GSTextureOGL::Unmap() { - // copy the texture to the GPU - // GLboolean glUnmapBuffer(GLenum target); -#if 0 - if(m_texture) - { - m_ctx->Unmap(m_texture, 0); + if (m_type == GSTexture::Offscreen) { + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); } -#endif } #ifndef _WINDOWS @@ -358,13 +377,13 @@ bool GSTextureOGL::Save(const string& fn, bool dds) // Collect the texture data char* image = (char*)malloc(4 * m_size.x * m_size.y); - if (m_type) { - EnableUnit(0); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); - } else { + if (IsBackbuffer()) { // TODO backbuffer glReadBuffer(GL_BACK); glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image); + } else { + EnableUnit(0); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); } // Build a BMP file diff --git a/plugins/GSdx/GSTextureOGL.h b/plugins/GSdx/GSTextureOGL.h index ba9f3bab53..81614385cb 100644 --- a/plugins/GSdx/GSTextureOGL.h +++ b/plugins/GSdx/GSTextureOGL.h @@ -30,7 +30,7 @@ class GSTextureOGL : public GSTexture GLuint m_texture_id; // the texture id uint m_texture_unit; // the texture unit offset uint m_extra_buffer_id; - bool m_extra_buffer_allocated; + int m_pbo_size; public: explicit GSTextureOGL(int type, int w, int h, bool msaa, int format);