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
This commit is contained in:
gregory.hainaut 2011-12-31 14:38:58 +00:00
parent 9ca65c9cc6
commit 2f4e2d8b6b
5 changed files with 111 additions and 76 deletions

View File

@ -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);
}

View File

@ -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<int>(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)

View File

@ -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<int>(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);

View File

@ -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)

View File

@ -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