gsdx-ogl: LINUX-ONLY

* improve vertex management with a vertex array. Decorrelate vertex from strech rec and others func (later for the HW renderer)
* fix the crash on nvidia when closing the window
* clean some texture management code


git-svn-id: http://pcsx2.googlecode.com/svn/branches/gsdx-ogl@4985 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gregory.hainaut 2011-12-10 19:19:44 +00:00
parent e6057b765f
commit daf3c43681
5 changed files with 101 additions and 48 deletions

View File

@ -57,10 +57,11 @@ GSDeviceOGL::GSDeviceOGL()
: m_free_window(false)
, m_window(NULL)
, m_vb(0)
, m_fbo(0)
, m_sr_vb_offset(0)
, m_pipeline(0)
, m_srv_changed(false)
, m_ss_changed(false)
, m_vb_changed(false)
{
m_msaa = theApp.GetConfig("msaa", 0);
@ -85,6 +86,8 @@ GSDeviceOGL::~GSDeviceOGL()
delete (m_interlace.cb);
// Clean m_convert
glDeleteVertexArrays(1, &m_convert.va);
glDeleteBuffers(1, &m_convert.vb);
glDeleteProgram(m_convert.vs);
for (uint i = 0; i < 2; i++)
glDeleteProgram(m_convert.ps[i]);
@ -176,14 +179,17 @@ bool GSDeviceOGL::Create(GSWnd* wnd)
OMSetFBO(m_fbo);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
OMSetFBO(0);
// ****************************************************************
// convert
// ****************************************************************
// There isn't a default VAO in newer versions of OpenGL, so create one.
unsigned int vao = 0;
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
glGenVertexArrays(1, &m_convert.va);
IASetVertexArrray(m_convert.va);
glGenBuffers(1, &m_convert.vb);
IASetVertexBufferBind(m_convert.vb);
glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(GSVertexPT1), NULL, GL_STREAM_DRAW);
GSInputLayout il_convert[2] =
{
@ -191,8 +197,14 @@ bool GSDeviceOGL::Create(GSWnd* wnd)
{1, 2, GL_FLOAT, sizeof(GSVertexPT1), (const GLvoid*)offsetof(struct GSVertexPT1, t) },
};
m_convert.il[0] = il_convert[0];
m_convert.il[1] = il_convert[1];
for (int i = 0; i < 2; i++) {
// Note this function need both a vertex array object and a GL_ARRAY_BUFFER buffer
glEnableVertexAttribArray(il_convert[i].index);
glVertexAttribPointer(il_convert[i].index, il_convert[i].size, il_convert[i].type, GL_FALSE, il_convert[i].stride, il_convert[i].offset);
}
// Unbind to avoid issue with the setup of others parameters
IASetVertexArrray(0);
IASetVertexBufferBind(0);
CompileShaderFromSource("convert.glsl", "vs_main", GL_VERTEX_SHADER, &m_convert.vs);
for(int i = 0; i < countof(m_convert.ps); i++)
@ -662,17 +674,25 @@ void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt,
return;
}
// ************************************
// Init
// ************************************
BeginScene();
GSVector2i ds = dt->GetSize();
// ************************************
// om
// ************************************
OMSetDepthStencilState(m_convert.dss, 0);
OMSetBlendState(bs, 0);
OMSetRenderTargets(dt, NULL);
// ************************************
// ia
// ************************************
float left = dr.x * 2 / ds.x - 1.0f;
float top = 1.0f - dr.y * 2 / ds.y;
@ -687,29 +707,44 @@ void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt,
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)},
};
IASetVertexBuffer(vertices, sizeof(vertices[0]), countof(vertices));
IASetInputLayout(m_convert.il, 2);
IASetPrimitiveTopology(GL_TRIANGLE_STRIP);
IASetVertexArrray(m_convert.va);
IASetVertexBufferBind(m_convert.vb);
// FIXME it will worth some benchmark.
// What is the faster always use the same. Or pack to difference emplacement. I'm afraid
// that in all case the GPU will be stall to wait the data
// Note maybe create a new buffer can be faster.
// m_sr_vb_offset = 0;
glBufferSubData(GL_ARRAY_BUFFER, m_sr_vb_offset * 4 * sizeof(GSVertexPT1) , sizeof(GSVertexPT1) * 4, vertices);
// ************************************
// vs
// ************************************
VSSetShader(m_convert.vs, NULL);
// ************************************
// gs
// ************************************
GSSetShader(0);
// ************************************
// ps
// ************************************
PSSetShaderResources(st, NULL);
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, 0);
PSSetShader(ps, ps_cb);
//
// ************************************
// Draw
// ************************************
glDrawArrays(GL_TRIANGLE_STRIP, m_sr_vb_offset * 4, 4);
m_sr_vb_offset = (m_sr_vb_offset + 1) & 0x3;
DrawPrimitive();
//
// ************************************
// End
// ************************************
EndScene();
@ -784,6 +819,22 @@ GSTexture* GSDeviceOGL::Resolve(GSTexture* t)
return NULL;
}
void GSDeviceOGL::IASetVertexArrray(GLuint va)
{
if (m_state.va != va) {
glBindVertexArray(va);
m_state.va = va;
}
}
void GSDeviceOGL::IASetVertexBufferBind(GLuint vb)
{
if (m_state.vb != vb) {
glBindBuffer(GL_ARRAY_BUFFER, vb);
m_state.vb = vb;
}
}
void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t count)
{
ASSERT(m_vertices.count == 0);
@ -799,15 +850,16 @@ void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t
m_vertices.start = 0;
m_vertices.count = 0;
m_vertices.limit = std::max<int>(count * 3 / 2, 11000);
m_vertices.stride = stride;
}
if(!m_vb)
{
glGenBuffers(1, &m_vb);
glBindBuffer(GL_ARRAY_BUFFER, m_vb);
glBufferData(GL_ARRAY_BUFFER, m_vertices.limit * stride, NULL, GL_STREAM_DRAW);
m_vb_changed = true;
IASetVertexBufferBind(m_vb);
// Allocate the buffer
glBufferData(GL_ARRAY_BUFFER, m_vertices.limit * m_vertices.stride, NULL, GL_STREAM_DRAW);
//m_vb_changed = true;
}
// append data or go back to the beginning
@ -815,14 +867,13 @@ void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t
if(m_vertices.start + count > m_vertices.limit || stride != m_vertices.stride)
m_vertices.start = 0;
// Allocate the buffer
// glBufferSubData
// Fill the buffer
glBufferSubData(GL_ARRAY_BUFFER, m_vertices.start * stride, count * stride, vertices);
m_vertices.count = count;
m_vertices.stride = stride;
}
#if 0
void GSDeviceOGL::IASetInputLayout(GSInputLayout* layout, int layout_nbr)
{
if(m_state.layout != layout || m_state.layout_nbr != layout_nbr || m_vb_changed)
@ -842,6 +893,7 @@ void GSDeviceOGL::IASetInputLayout(GSInputLayout* layout, int layout_nbr)
m_state.layout_nbr = layout_nbr;
}
}
#endif
void GSDeviceOGL::IASetPrimitiveTopology(GLenum topology)
{

View File

@ -107,6 +107,7 @@ class GSDeviceOGL : public GSDevice
GLuint m_vb; // vertex buffer object
GLuint m_pipeline; // pipeline to attach program shader
GLuint m_fbo; // frame buffer container
uint32 m_sr_vb_offset;
struct {
GLuint ps[2]; // program object
@ -123,7 +124,9 @@ class GSDeviceOGL : public GSDevice
// Hum I think this one is useless. As far as I understand
// it only get the index name of GLSL-equivalent input attribut
// ??? CComPtr<ID3D11InputLayout> il;
GSInputLayout il[2]; // description of the vertex array
//GSInputLayout il[2]; // description of the vertex array
GLuint va; // vertex array object
GLuint vb; // vertex buffer
GLuint vs; // program object
GLuint ps[8]; // program object
GLuint ln; // sampler object
@ -162,12 +165,13 @@ class GSDeviceOGL : public GSDevice
// } m_state;
struct
{
GLuint vb;
GLuint vb; // vertex buffer
// Hum I think those things can be dropped on OGL. It probably need an others architecture (see glVertexAttribPointer)
// size_t vb_stride;
// ID3D11InputLayout* layout;
GSInputLayout* layout;
uint32 layout_nbr;
//GSInputLayout* layout;
//uint32 layout_nbr;
GLuint va; // vertex array
GLenum topology; // (ie GL_TRIANGLES...)
GLuint vs; // program
GLuint cb; // uniform current buffer
@ -195,7 +199,7 @@ class GSDeviceOGL : public GSDevice
bool m_srv_changed;
bool m_ss_changed;
bool m_vb_changed;
//bool m_vb_changed;
#if 0
CComPtr<ID3D11Device> m_dev;
@ -271,8 +275,10 @@ class GSDeviceOGL : public GSDevice
void CompileShaderFromSource(const std::string& glsl_file, const std::string& entry, GLenum type, GLuint* program);
void IASetPrimitiveTopology(GLenum topology);
void IASetInputLayout(GSInputLayout* layout, int layout_nbr);
//void IASetInputLayout(GSInputLayout* layout, int layout_nbr);
void IASetVertexBuffer(const void* vertices, size_t stride, size_t count);
void IASetVertexBufferBind(GLuint vb);
void IASetVertexArrray(GLuint va);
void VSSetShader(GLuint vs, GSUniformBufferOGL* vs_cb);
void GSSetShader(GLuint gs);

View File

@ -22,6 +22,8 @@
#pragma once
#include "GSTextureOGL.h"
static uint g_state_texture_unit = 0;
static uint g_state_texture_id = 0;
GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format)
: m_texture_unit(0),
@ -93,13 +95,8 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format)
// Generate the buffer
switch (m_type) {
case GSTexture::Texture:
case GSTexture::RenderTarget:
// FIXME what is the real use case of this texture
// Maybe a texture will be better
// glGenRenderbuffers(1, &m_texture_id);
// m_texture_target = GL_RENDERBUFFER;
// Buffer can not be read by shader and must be blit before. I see no point to use a render buffer
// when you can directly render on the texture. It said it could be faster...
glGenTextures(1, &m_texture_id);
m_texture_target = GL_TEXTURE_2D;
break;
@ -107,13 +104,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::Texture:
glGenTextures(1, &m_texture_id);
// FIXME, do we need rectangle (or better to use 2D texture)
m_texture_target = GL_TEXTURE_2D;
//m_texture_target = GL_TEXTURE_RECTANGLE;
// == For texture, the Unit must be selected
break;
case GSTexture::Offscreen:
//FIXME I not sure we need a pixel buffer object. It seems more a texture
// glGenBuffers(1, &m_texture_id);
@ -156,7 +146,7 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format)
glTexImage2D(m_texture_target, 0, m_format, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
}
else
assert(0);
assert(0); // TODO Later
break;
case GSTexture::Offscreen:
assert(0);
@ -252,8 +242,16 @@ void GSTextureOGL::EnableUnit(uint unit)
// 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
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(m_texture_target, m_texture_id);
if (g_state_texture_unit != unit) {
g_state_texture_unit = unit;
glActiveTexture(GL_TEXTURE0 + unit);
// When you change the texture unit, texture must be rebinded
g_state_texture_id = m_texture_id;
glBindTexture(m_texture_target, m_texture_id);
} else if (g_state_texture_id != m_texture_id) {
g_state_texture_id = m_texture_id;
glBindTexture(m_texture_target, m_texture_id);
}
break;
}
}

View File

@ -363,8 +363,7 @@ bool GSWnd::Attach(void* handle, bool managed)
GLXFBConfig *fbc = glXChooseFBConfig(m_XDisplay, DefaultScreen(m_XDisplay), attrListDbl, &fbcount);
if (!fbc || fbcount < 1) return false;
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddress((const GLubyte*) "glXCreateContextAttribsARB");
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte*) "glXCreateContextAttribsARB");
if (!glXCreateContextAttribsARB) return false;
// Create a context
@ -407,7 +406,7 @@ void GSWnd::Detach()
m_window = NULL;
}
} else {
glXMakeCurrent(m_XDisplay, m_Xwindow, 0);
glXMakeCurrent(m_XDisplay, None, NULL);
if (m_context) glXDestroyContext(m_XDisplay, m_context);
}
if (m_XDisplay) {

View File

@ -91,8 +91,6 @@ public:
#include "../../3rdparty/SDL-1.3.0-5387/include/SDL.h"
#include "../../3rdparty/SDL-1.3.0-5387/include/SDL_syswm.h"
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, bool, const int*);
class GSWnd
{
SDL_Window* m_window;