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
This commit is contained in:
gregory.hainaut 2012-03-05 20:16:26 +00:00
parent 92f2ab38ae
commit d6e7ea4a4e
5 changed files with 116 additions and 74 deletions

View File

@ -21,6 +21,10 @@
#include "GSDeviceOGL.h" #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 LOUD_DEBUGGING
//#define PRINT_FRAME_NUMBER //#define PRINT_FRAME_NUMBER
//#define ONLY_LINES //#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)); 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)); //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); fprintf(stderr, "Draw %d (Frame %d)\n", g_draw_count, g_frame_count);
@ -520,6 +524,8 @@ void GSDeviceOGL::DebugInput()
void GSDeviceOGL::DebugOutput() void GSDeviceOGL::DebugOutput()
{ {
CheckDebugLog();
bool dump_me = false; bool dump_me = false;
uint32 start = theApp.GetConfig("debug_ogl_dump", 0); uint32 start = theApp.GetConfig("debug_ogl_dump", 0);
uint32 length = theApp.GetConfig("debug_ogl_dump_length", 5); uint32 length = theApp.GetConfig("debug_ogl_dump_length", 5);
@ -536,7 +542,6 @@ void GSDeviceOGL::DebugOutput()
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
CheckDebugLog();
} }
void GSDeviceOGL::DrawPrimitive() void GSDeviceOGL::DrawPrimitive()
@ -596,12 +601,7 @@ void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
// FIXME1 I need to clarify this FBO attachment stuff // FIXME1 I need to clarify this FBO attachment stuff
// I would like to avoid FBO for a basic clean operation // I would like to avoid FBO for a basic clean operation
OMSetFBO(m_fbo); OMSetFBO(m_fbo);
// FIXME2: glDrawBuffer(GL_COLOR_ATTACHMENT0);
// 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...
static_cast<GSTextureOGL*>(t)->Attach(GL_COLOR_ATTACHMENT0); static_cast<GSTextureOGL*>(t)->Attach(GL_COLOR_ATTACHMENT0);
glClearBufferfv(GL_COLOR, 0, c.v); glClearBufferfv(GL_COLOR, 0, c.v);
} }
@ -673,8 +673,8 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w
return false; return false;
} }
// FIXME: I used directly an offscreen texture because they are the same on Opengl // FIXME: It is possible to bypass completely offscreen-buffer on opengl but it needs some re-thinking of the code.
//if(GSTexture* rt = CreateRenderTarget(w, h, false, format)) // For the moment mimic dx11
GSTexture* rt = CreateRenderTarget(w, h, false, format); GSTexture* rt = CreateRenderTarget(w, h, false, format);
if(rt) if(rt)
{ {
@ -687,9 +687,12 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w
if(src2 != src) Recycle(src2); if(src2 != src) Recycle(src2);
} }
#if 0
GSVector4i dor(0, 0, w, h);
dst = CreateOffscreen(w, h, format); dst = CreateOffscreen(w, h, format);
if (dst) CopyRect(rt, dst, dor);
#if 0
if(dst) if(dst)
{ {
m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt); m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt);
@ -699,8 +702,8 @@ GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w
Recycle(rt); Recycle(rt);
} }
//return dst; return dst;
return rt; //return rt;
} }
// Copy a sub part of a texture into another // 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 srcName, enum srcTarget, int srcLevel, int srcX, int srcY, int srcZ,
// uint dstName, enum dstTarget, int dstLevel, int dstX, int dstY, int dstZ, // uint dstName, enum dstTarget, int dstLevel, int dstX, int dstY, int dstZ,
// sizei width, sizei height, sizei depth); // sizei width, sizei height, sizei depth);
glCopyImageSubDataNV( static_cast<GSTextureOGL*>(st)->GetID(), GL_TEXTURE_2D, glCopyImageSubDataNV( static_cast<GSTextureOGL*>(st)->GetID(), static_cast<GSTextureOGL*>(st)->GetTarget(),
0, r.x, r.y, 0, 0, r.x, r.y, 0,
static_cast<GSTextureOGL*>(dt)->GetID(), GL_TEXTURE_2D, static_cast<GSTextureOGL*>(dt)->GetID(), static_cast<GSTextureOGL*>(dt)->GetTarget(),
0, r.x, r.y, 0, 0, r.x, r.y, 0,
r.width(), r.height(), 1); 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<GSTextureOGL*>(st)->Attach(GL_COLOR_ATTACHMENT1);
glReadBuffer(GL_COLOR_ATTACHMENT1);
// Copy the full image
static_cast<GSTextureOGL*>(dt)->EnableUnit(0);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, dt->GetWidth(), dt->GetHeight());
OMSetFBO(fbo_old);
#endif
#if 0 #if 0
D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1};

View File

@ -62,10 +62,27 @@ GtkWidget* CreateRenderComboBox()
if(!s.note.empty()) label += format(" (%s)", s.note.c_str()); if(!s.note.empty()) label += format(" (%s)", s.note.c_str());
// (dev only) for any NULL stuff // Add some tags to ease users selection
if (i >= 7 && i <= 9) label += " (debug only)"; switch (i) {
// (experimental) for opengl stuff // better use opengl instead of SDL
if (i == 10 || i == 11) label += " (experimental)"; 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()); gtk_combo_box_append_text(GTK_COMBO_BOX(render_combo_box), label.c_str());
} }

View File

@ -96,7 +96,7 @@ void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r)
offscreen->Unmap(); offscreen->Unmap();
} }
//m_renderer->m_dev->Recycle(offscreen); m_renderer->m_dev->Recycle(offscreen);
} }
} }

View File

@ -26,7 +26,7 @@ static int g_state_texture_unit = -1;
static int g_state_texture_id = -1; static int g_state_texture_id = -1;
GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint fbo_read) 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) m_pbo_size(0)
{ {
// ************************************************************* // *************************************************************
@ -48,8 +48,11 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint
// glBlitFramebuffer // glBlitFramebuffer
// ************************************************************* // *************************************************************
m_size.x = w; // m_size.x = w;
m_size.y = h; // m_size.y = h;
// FIXME
m_size.x = max(1,w);
m_size.y = max(1,h);
m_format = format; m_format = format;
m_type = type; m_type = type;
m_msaa = msaa; m_msaa = msaa;
@ -80,7 +83,7 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint
break; break;
} }
// Extra buffer to handle various pixel transfer // Extra buffer to handle various pixel transfer
glGenBuffers(1, &m_extra_buffer_id); glGenBuffers(1, &m_pbo_id);
uint msaa_level; uint msaa_level;
if (m_msaa) { if (m_msaa) {
@ -93,16 +96,30 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format, GLuint
// Allocate the buffer // Allocate the buffer
switch (m_type) { switch (m_type) {
case GSTexture::DepthStencil: 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); 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; 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::RenderTarget:
case GSTexture::Texture: case GSTexture::Texture:
// FIXME // FIXME
// Howto allocate the texture unit !!! // Howto allocate the texture unit !!!
// In worst case the HW renderer seems to use 3 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 // For the moment SW renderer only use 1 so don't bother
EnableUnit(2); EnableUnit(0);
if (m_format == GL_RGBA8) 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); 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) 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 assert(0); // TODO Later
} }
break; 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; default: break;
} }
} }
GSTextureOGL::~GSTextureOGL() GSTextureOGL::~GSTextureOGL()
{ {
glDeleteBuffers(1, &m_extra_buffer_id); glDeleteBuffers(1, &m_pbo_id);
glDeleteTextures(1, &m_texture_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 warning order of the y axis
// FIXME I'm not confident with GL_UNSIGNED_BYTE type // FIXME I'm not confident with GL_UNSIGNED_BYTE type
EnableUnit(2); EnableUnit(0);
// pitch could be different of width*element_size // pitch could be different of width*element_size
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch>>2); 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 // glMapBuffer — map a buffer object's data store
// Can be used on GL_PIXEL_UNPACK_BUFFER or GL_TEXTURE_BUFFER // Can be used on GL_PIXEL_UNPACK_BUFFER or GL_TEXTURE_BUFFER
if (m_type == GSTexture::Offscreen) { if (m_type == GSTexture::Offscreen) {
glBindBuffer(GL_PIXEL_PACK_BUFFER, m_extra_buffer_id); // Bind the texture to the read framebuffer to avoid any disturbance
// FIXME It might be possible to only map a subrange of the texture based on r object 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 // FIXME It might be possible to only read a subrange of the texture based on r object
if (m_format == GL_RGBA8) // 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); 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); 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); 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); fprintf(stderr, "wrong texture pixel format :%x\n", m_format);
assert(0); assert(0);
} }
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// Give access from the CPU // Give access from the CPU
uint32 map_flags = GL_MAP_READ_BIT; m.bits = (uint8*) glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pbo_size, GL_MAP_READ_BIT);
m.bits = (uint8*) glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, m_pbo_size, map_flags);
m.pitch = m_size.x; m.pitch = m_size.x;
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); if ( m.bits ) {
return true;
return true; } else {
fprintf(stderr, "bad mapping of the pbo\n");
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
return false;
}
} }
return false; return false;
@ -272,6 +292,8 @@ void GSTextureOGL::Unmap()
{ {
if (m_type == GSTexture::Offscreen) { if (m_type == GSTexture::Offscreen) {
glUnmapBuffer(GL_PIXEL_PACK_BUFFER); 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; uint32 pitch = 4 * m_size.x;
if (IsDss()) pitch *= 2; if (IsDss()) pitch *= 2;
char* image = (char*)malloc(pitch * m_size.y); 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 // FIXME instead of swapping manually B and R maybe you can request the driver to do it
// for us // for us
if (IsBackbuffer()) { 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); glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image);
} else if(IsDss()) { } else if(IsDss()) {
EnableUnit(2); EnableUnit(0);
glGetTexImage(m_texture_target, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, image); glGetTexImage(m_texture_target, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, image);
} else { } else {
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read); glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
EnableUnit(2); EnableUnit(0);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, m_texture_target, m_texture_id, 0); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture_target, m_texture_id, 0);
glReadBuffer(GL_COLOR_ATTACHMENT1); glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image); 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); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
} }
Save(fn, image, pitch); if (status) Save(fn, image, pitch);
free(image); free(image);
return true; return status;
} }

View File

@ -28,7 +28,7 @@ class GSTextureOGL : public GSTexture
private: private:
GLenum m_texture_target; // texture target: 2D, rectangle etc... GLenum m_texture_target; // texture target: 2D, rectangle etc...
GLuint m_texture_id; // the texture id GLuint m_texture_id; // the texture id
uint m_extra_buffer_id; uint m_pbo_id;
int m_pbo_size; int m_pbo_size;
GLuint m_fbo_read; GLuint m_fbo_read;
@ -49,4 +49,5 @@ class GSTextureOGL : public GSTexture
bool IsDss() { return (m_type == GSTexture::DepthStencil); } bool IsDss() { return (m_type == GSTexture::DepthStencil); }
GLuint GetID() { return m_texture_id; } GLuint GetID() { return m_texture_id; }
GLenum GetTarget() { return m_texture_target; }
}; };