From a835de0af706a65c4da6719ff16d38de5f571d06 Mon Sep 17 00:00:00 2001 From: "gregory.hainaut" Date: Wed, 7 Dec 2011 22:05:46 +0000 Subject: [PATCH] gsdx-ogl: LINUX-ONLY * implement the saving of texture (take bmp SW code) * fix the missing "enable attribute code" and the typo in glsl. It works now !!! * rework a little texture to pack texture into a temporay buffer when src pitch != dst pitch * try to replace sdl with pure xlib (not yet enabled by default but it seems to work) Note there still a minor issue, coordinate are different between DX and OGL (upper-left vs lower-left) so the image is inversed. git-svn-id: http://pcsx2.googlecode.com/svn/branches/gsdx-ogl@4981 96395faa-99c1-11dd-bbfe-3dabce05a288 --- cmake/BuildParameters.cmake | 2 +- plugins/GSdx/CMakeLists.txt | 7 ++ plugins/GSdx/GSDeviceOGL.cpp | 98 +++++++++++------- plugins/GSdx/GSDeviceOGL.h | 11 ++ plugins/GSdx/GSTextureOGL.cpp | 174 +++++++++++++++++++++++++++----- plugins/GSdx/GSTextureOGL.h | 2 + plugins/GSdx/GSVertex.h | 6 +- plugins/GSdx/GSWnd.cpp | 105 +++++++++++++++++-- plugins/GSdx/GSWnd.h | 5 + plugins/GSdx/res/convert.glsl | 25 ++++- plugins/GSdx/res/interlace.glsl | 2 +- plugins/GSdx/res/merge.glsl | 6 +- 12 files changed, 358 insertions(+), 85 deletions(-) diff --git a/cmake/BuildParameters.cmake b/cmake/BuildParameters.cmake index 764cdc8748..64625089f5 100644 --- a/cmake/BuildParameters.cmake +++ b/cmake/BuildParameters.cmake @@ -119,7 +119,7 @@ set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") #------------------------------------------------------------------------------- # Set some default compiler flags #------------------------------------------------------------------------------- -set(DEFAULT_WARNINGS "-Wno-write-strings -Wno-format -Wno-unused-parameter -Wno-unused-value -Wstrict-aliasing") +set(DEFAULT_WARNINGS "-w -Wno-write-strings -Wno-format -Wno-unused-parameter -Wno-unused-value -Wstrict-aliasing") set(DEFAULT_GCC_FLAG "-m32 -msse -msse2 -march=i686 -pthread ${DEFAULT_WARNINGS}") set(DEFAULT_CPP_FLAG "${DEFAULT_GCC_FLAG} -Wno-invalid-offsetof") diff --git a/plugins/GSdx/CMakeLists.txt b/plugins/GSdx/CMakeLists.txt index 264ca8ce99..57aa7d1531 100644 --- a/plugins/GSdx/CMakeLists.txt +++ b/plugins/GSdx/CMakeLists.txt @@ -16,6 +16,7 @@ set(CommonFlags -mfpmath=sse #-Wstrict-aliasing # Allow to track strict aliasing issue. -Wunused-variable + -DKEEP_SDL ) set(OptimizationFlags @@ -196,6 +197,12 @@ endif(NOT USER_CMAKE_LD_FLAGS STREQUAL "") if(PACKAGE_MODE) install(TARGETS ${Output} DESTINATION ${PLUGIN_DIR}) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/convert.glsl DESTINATION ${PLUGIN_DIR}) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/interlace.glsl DESTINATION ${PLUGIN_DIR}) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/merge.glsl DESTINATION ${PLUGIN_DIR}) else(PACKAGE_MODE) install(TARGETS ${Output} DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/convert.glsl DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/interlace.glsl DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) + install(FILES ${PROJECT_SOURCE_DIR}/plugins/GSdx/res/merge.glsl DESTINATION ${CMAKE_SOURCE_DIR}/bin/plugins) endif(PACKAGE_MODE) diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp index e3248b8dd7..9aae22efba 100644 --- a/plugins/GSdx/GSDeviceOGL.cpp +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -62,8 +62,13 @@ GSDeviceOGL::GSDeviceOGL() , m_pipeline(0) , m_srv_changed(false) , m_ss_changed(false) + , m_vb_changed(false) { m_msaa = theApp.GetConfig("msaa", 0); + + m_frag_back_buffer[0] = GL_BACK_LEFT; + m_frag_rt_buffer[0] = GL_COLOR_ATTACHMENT0; + memset(&m_merge, 0, sizeof(m_merge)); memset(&m_interlace, 0, sizeof(m_interlace)); memset(&m_convert, 0, sizeof(m_convert)); @@ -102,13 +107,17 @@ GSDeviceOGL::~GSDeviceOGL() glDeleteProgramPipelines(1, &m_pipeline); glDeleteFramebuffers(1, &m_fbo); + // glXMakeCurrent(m_XDisplay, m_Xwindow, 0); + // if (m_context) glXDestroyContext(m_XDisplay, m_context); // if(m_context) // SDL_GL_DeleteContext(m_context); +#ifdef KEEP_SDL if(m_dummy_renderer) SDL_DestroyRenderer(m_dummy_renderer); if(m_window != NULL && m_free_window) SDL_DestroyWindow(m_window); +#endif } GSTexture* GSDeviceOGL::CreateSurface(int type, int w, int h, bool msaa, int format) @@ -149,11 +158,8 @@ PFNGLTEXSTORAGE2DPROC glTexStorage2D_glew17 = NULL; bool GSDeviceOGL::Create(GSWnd* wnd) { if (m_window == NULL) { -#if SDL_VERSION_ATLEAST(1,3,0) +#ifdef KEEP_SDL m_window = SDL_CreateWindowFrom(wnd->GetHandle()); -#else - assert(0); -#endif m_free_window = true; // If the user request OpenGL acceleration, we take recent OGL version (4.2) @@ -168,7 +174,7 @@ bool GSDeviceOGL::Create(GSWnd* wnd) // Ask for an advance opengl version SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 ); // FIXME AMD does not support yet 4.2... - //SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 ); + //SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 ); // Window must be recreated to gain Opengl feature... @@ -177,7 +183,7 @@ bool GSDeviceOGL::Create(GSWnd* wnd) m_dummy_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED); // SDL_RENDERER_PRESENTVSYNC // At least create the opengl context // m_context = SDL_GL_CreateContext(m_window); - +#endif // FIXME...... // GLEW's problem is that it calls glGetString(GL_EXTENSIONS) which causes GL_INVALID_ENUM on GL 3.2 forward compatible context as soon as glewInit() is called. It also doesn't fetch the function pointers. The solution is for GLEW to use glGetStringi instead. @@ -202,10 +208,12 @@ bool GSDeviceOGL::Create(GSWnd* wnd) glTexStorage2D_glew17 = (PFNGLTEXSTORAGE2DPROC)glXGetProcAddressARB((const GLubyte*)"glTexStorage2D"); } -#ifdef __LINUX__ +#ifdef KEEP_SDL // In GSopen2, sdl failed to received any resize event. GSWnd::GetClientRect need to manually // set the window size... So we send the m_window to the wnd object to allow some manipulation on it. wnd->SetWindow(m_window); +#else + m_window = wnd; #endif // FIXME disable it when code is ready @@ -529,13 +537,7 @@ void GSDeviceOGL::Flip() { // FIXME: disable it when code is working CheckDebugLog(); - // Warning it is not OGL dependent but application dependant (glx and so not portable) -#if SDL_VERSION_ATLEAST(1,3,0) - SDL_GL_SwapWindow(m_window); -#else - SDL_GL_SwapBuffers(); -#endif - + m_wnd->Flip(); } void GSDeviceOGL::DrawPrimitive() @@ -546,18 +548,29 @@ void GSDeviceOGL::DrawPrimitive() void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c) { GSTextureOGL* t_ogl = (GSTextureOGL*)t; - // FIXME I need to clarify this FBO attachment stuff - // I would like to avoid FBO for a basic clean operation - //glClearBufferfv(GL_COLOR, t_ogl->attachment(), c.v); + if (t == m_backbuffer) { + // FIXME need an assert + if (m_state.fbo) { + m_state.fbo = 0; + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + glClearBufferfv(GL_COLOR, GL_BACK, c.v); + } else { + // FIXME I need to clarify this FBO attachment stuff + // I would like to avoid FBO for a basic clean operation + if (!m_state.fbo) { + m_state.fbo = m_fbo; + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + } + t_ogl->Attach(GL_COLOR_ATTACHMENT0); + glClearBufferfv(GL_COLOR, 0, c.v); + } } void GSDeviceOGL::ClearRenderTarget(GSTexture* t, uint32 c) { - GSTextureOGL* t_ogl = (GSTextureOGL*)t; GSVector4 color = GSVector4::rgba32(c) * (1.0f / 255); - // FIXME I need to clarify this FBO attachment stuff - // I would like to avoid FBO for a basic clean operation - //glClearBufferfv(GL_COLOR, t_ogl->attachment(), color.v); + ClearRenderTarget(t, color); } void GSDeviceOGL::ClearDepth(GSTexture* t, float c) @@ -691,9 +704,9 @@ void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear); } -// probably no difficult to convert when all helpers function will be done void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, GSUniformBufferOGL* ps_cb, GSBlendStateOGL* bs, bool linear) { + if(!st || !dt) { ASSERT(0); @@ -717,8 +730,7 @@ void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, float right = dr.z * 2 / ds.x - 1.0f; float bottom = 1.0f - dr.w * 2 / ds.y; - //FIXME aligment issue - GSVertexPT1 vertices[] __attribute__ ((aligned (16))) = + GSVertexPT1 vertices[] = { {GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)}, {GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)}, @@ -745,6 +757,12 @@ void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, PSSetShader(ps, ps_cb); // + // FIXME: disable it when code is working + glValidateProgramPipeline(m_pipeline); + GLint status; + glGetProgramPipelineiv(m_pipeline, GL_VALIDATE_STATUS, &status); + if (status != GL_TRUE) + fprintf(stderr, "Failed to validate the pipeline\n"); DrawPrimitive(); @@ -797,7 +815,6 @@ void GSDeviceOGL::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool lin m_state.cb = m_interlace.cb->buffer; glBindBuffer(GL_UNIFORM_BUFFER, m_interlace.cb->buffer); } - // FIXME I'm not sure it will be happy with InterlaceConstantBuffer type glBufferSubData(GL_UNIFORM_BUFFER, 0, m_interlace.cb->byte_size, &cb); #if 0 m_ctx->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0); @@ -842,6 +859,7 @@ void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t m_vertices.start = 0; m_vertices.count = 0; m_vertices.limit = std::max(count * 3 / 2, 11000); + } if(!m_vb) @@ -850,6 +868,7 @@ void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t // FIXME: GL_DYNAMIC_DRAW vs GL_STREAM_DRAW !!! glBindBuffer(GL_ARRAY_BUFFER, m_vb); glBufferData(GL_ARRAY_BUFFER, m_vertices.limit * stride, NULL, GL_DYNAMIC_DRAW); + m_vb_changed = true; } // append data or go back to the beginning @@ -867,12 +886,21 @@ void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t void GSDeviceOGL::IASetInputLayout(GSInputLayout* layout, int layout_nbr) { - if(m_state.layout != layout) + if(m_state.layout != layout || m_state.layout_nbr != layout_nbr || m_vb_changed) { - m_state.layout = layout; + // Remove old configuration. + for (int i = m_state.layout_nbr ; i > (m_state.layout_nbr - layout_nbr) ; i--) { + glDisableVertexAttribArray(i); + } - for (int i = 0; i < layout_nbr; i++) - glVertexAttribPointer(layout->index, layout->size, layout->type, GL_FALSE, layout->stride, layout->offset); + for (int i = 0; i < layout_nbr; i++) { + glEnableVertexAttribArray(layout[i].index); + glVertexAttribPointer(layout[i].index, layout[i].size, layout[i].type, GL_FALSE, layout[i].stride, layout[i].offset); + } + + m_vb_changed = false; + m_state.layout = layout; + m_state.layout_nbr = layout_nbr; } } @@ -1066,6 +1094,7 @@ void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVecto if (m_state.fbo) { m_state.fbo = 0; glBindFramebuffer(GL_FRAMEBUFFER, 0); // render in the backbuffer + glDrawBuffers(1, m_frag_back_buffer); } assert(ds_ogl == NULL); // no depth-stencil without FBO @@ -1073,6 +1102,7 @@ void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVecto if (m_state.fbo != m_fbo) { m_state.fbo = m_fbo; glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glDrawBuffers(1, m_frag_rt_buffer); } assert(rt_ogl != NULL); // a render target must exists @@ -1094,12 +1124,7 @@ void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVecto if(!m_state.scissor.eq(r)) { m_state.scissor = r; - // FIXME check position - // x = 0, - // y = 0, - // z = 512, - // w = 512 - glScissor(r.x, r.y, r.z-r.x, r.w-r.y); + glScissor( r.x, r.y, r.width(), r.height() ); #if 0 m_ctx->RSSetScissorRects(1, r); #endif @@ -1187,7 +1212,8 @@ void GSDeviceOGL::CompileShaderFromSource(const std::string& glsl_file, const st char* log = (char*)malloc(log_length); glGetProgramInfoLog(*program, log_length, NULL, log); - fprintf(stderr, "%s", log); + fprintf(stderr, "%s (%s) :", glsl_file.c_str(), entry.c_str()); + fprintf(stderr, "%s\n", log); free(log); } diff --git a/plugins/GSdx/GSDeviceOGL.h b/plugins/GSdx/GSDeviceOGL.h index d131fe6db0..b734390fdc 100644 --- a/plugins/GSdx/GSDeviceOGL.h +++ b/plugins/GSdx/GSDeviceOGL.h @@ -103,7 +103,11 @@ class GSDeviceOGL : public GSDevice uint32 m_msaa; // Level of Msaa bool m_free_window; +#ifdef KEEP_SDL SDL_Window* m_window; // pointer to the SDL window +#else + GSWnd* m_window; // pointer to the SDL window +#endif //SDL_GLContext m_context; // current opengl context SDL_Renderer* m_dummy_renderer; // ... crappy API ... @@ -111,6 +115,9 @@ class GSDeviceOGL : public GSDevice GLuint m_pipeline; // pipeline to attach program shader GLuint m_fbo; // frame buffer container + GLenum m_frag_back_buffer[1]; + GLenum m_frag_rt_buffer[1]; + struct { GLuint ps[2]; // program object GSUniformBufferOGL* cb; // uniform buffer object @@ -170,6 +177,7 @@ class GSDeviceOGL : public GSDevice // size_t vb_stride; // ID3D11InputLayout* layout; GSInputLayout* layout; + uint32 layout_nbr; GLenum topology; // (ie GL_TRIANGLES...) GLuint vs; // program GLuint cb; // uniform current buffer @@ -197,6 +205,7 @@ class GSDeviceOGL : public GSDevice bool m_srv_changed; bool m_ss_changed; + bool m_vb_changed; #if 0 CComPtr m_dev; @@ -229,6 +238,8 @@ class GSDeviceOGL : public GSDevice PSConstantBuffer m_ps_cb_cache; #endif + //GLenum frag_back[1] = { GL_BACK }; + //GLenum frag_target[1] = { GL_COLOR_ATTACHMENT0 }: void CheckDebugLog(); void DebugOutputToFile(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, const char* message); diff --git a/plugins/GSdx/GSTextureOGL.cpp b/plugins/GSdx/GSTextureOGL.cpp index 9c3a679e38..21b6518828 100644 --- a/plugins/GSdx/GSTextureOGL.cpp +++ b/plugins/GSdx/GSTextureOGL.cpp @@ -24,7 +24,9 @@ #include "GSTextureOGL.h" GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format) - : m_texture_unit(0) + : m_texture_unit(0), + m_extra_buffer_id(0), + m_extra_buffer_allocated(false) { // ************************************************************* // Opengl world @@ -123,8 +125,11 @@ GSTextureOGL::GSTextureOGL(int type, int w, int h, bool msaa, int format) // gvec texelFetch(gsampler sampler, ivec texCoord, int lod[, int sample]); // corollary we can maybe use it for multisample stuff break; - default: break; + default: + break; } + // Extra buffer to handle various pixel transfer + glGenBuffers(1, &m_extra_buffer_id); uint msaa_level; if (m_msaa) { @@ -178,31 +183,51 @@ void GSTextureOGL::Attach(GLenum attachment) bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch) { + // static int update_count = 0; + // update_count++; // To update only a part of the texture you can use: // glTexSubImage2D — specify a two-dimensional texture subimage - switch (m_type) { - case GSTexture::RenderTarget: - case GSTexture::Texture: - // glTexSubImage2D specifies a two-dimensional subtexture for the current texture unit, specified with glActiveTexture. - // If a non-zero named buffer object is bound to the GL_PIXEL_UNPACK_BUFFER target - //(see glBindBuffer) while a texture image is - // specified, data is treated as a byte offset into the buffer object's data store - // FIXME warning order of the y axis - // FIXME I'm not confident with GL_UNSIGNED_BYTE type - // FIXME add a state check - glBindTexture(m_texture_target, m_texture_id); - //void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * data); - // fprintf(stderr, "texture coord %d, %d, %d, %d\n", r.x, r.y, r.z, r.w); - if (m_format == GL_RGBA8) - glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.z-r.x, r.w-r.y, GL_RGBA, GL_UNSIGNED_BYTE, data); - else - assert(0); - break; - case GSTexture::DepthStencil: - case GSTexture::Offscreen: - assert(0); - break; + if (m_type == GSTexture::DepthStencil || m_type == GSTexture::Offscreen) assert(0); + + // glTexSubImage2D specifies a two-dimensional subtexture for the current texture unit, specified with glActiveTexture. + // If a non-zero named buffer object is bound to the GL_PIXEL_UNPACK_BUFFER target + //(see glBindBuffer) while a texture image is + // specified, data is treated as a byte offset into the buffer object's data store + // FIXME warning order of the y axis + // FIXME I'm not confident with GL_UNSIGNED_BYTE type + // FIXME add a state check + + EnableUnit(0); + + if (m_format != GL_RGBA8) assert(0); + + // FIXME. That suck but I don't know how to do better for now. I think we need to create a texture buffer and directly upload the copy + // The case appears on SW mode. Src pitch is 2x dst pitch. + int rowbytes = r.width() << 2; + if (pitch != rowbytes) { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_extra_buffer_id); + + if (!m_extra_buffer_allocated) { + glBufferData(GL_PIXEL_UNPACK_BUFFER, m_size.x * m_size.y * 4, NULL, GL_STREAM_DRAW); + m_extra_buffer_allocated = true; + } + + uint8* src = (uint8*) data; + uint8* dst = (uint8*) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + for(int h = r.height(); h > 0; h--, src += pitch, dst += rowbytes) + { + memcpy(dst, src, rowbytes); + } + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + + glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, 0 /* offset in UNPACK BUFFER */); + + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + } else { + glTexSubImage2D(m_texture_target, 0, r.x, r.y, r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE, data); } + #if 0 if(m_dev && m_texture) { @@ -283,10 +308,107 @@ void GSTextureOGL::Unmap() #endif } -// If I'm correct, this function only dump some buffer. Debug only, still very useful! -// Note: check zzogl implementation +#ifndef _WINDOWS + +#pragma pack(push, 1) + +struct BITMAPFILEHEADER +{ + uint16 bfType; + uint32 bfSize; + uint16 bfReserved1; + uint16 bfReserved2; + uint32 bfOffBits; +}; + +struct BITMAPINFOHEADER +{ + uint32 biSize; + int32 biWidth; + int32 biHeight; + uint16 biPlanes; + uint16 biBitCount; + uint32 biCompression; + uint32 biSizeImage; + int32 biXPelsPerMeter; + int32 biYPelsPerMeter; + uint32 biClrUsed; + uint32 biClrImportant; +}; + +#define BI_RGB 0 + +#pragma pack(pop) + +#endif + bool GSTextureOGL::Save(const string& fn, bool dds) { + switch (m_type) { + case GSTexture::DepthStencil: + case GSTexture::Offscreen: + ASSERT(0); + break; + default: break; + } + + // 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 { + // TODO backbuffer + glReadBuffer(GL_BACK); + glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image); + } + + // Build a BMP file + if(FILE* fp = fopen(fn.c_str(), "wb")) + { + BITMAPINFOHEADER bih; + + memset(&bih, 0, sizeof(bih)); + + bih.biSize = sizeof(bih); + bih.biWidth = m_size.x; + bih.biHeight = m_size.y; + bih.biPlanes = 1; + bih.biBitCount = 32; + bih.biCompression = BI_RGB; + bih.biSizeImage = m_size.x * m_size.y << 2; + + BITMAPFILEHEADER bfh; + + memset(&bfh, 0, sizeof(bfh)); + + uint8* bfType = (uint8*)&bfh.bfType; + + // bfh.bfType = 'MB'; + bfType[0] = 0x42; + bfType[1] = 0x4d; + bfh.bfOffBits = sizeof(bfh) + sizeof(bih); + bfh.bfSize = bfh.bfOffBits + bih.biSizeImage; + bfh.bfReserved1 = bfh.bfReserved2 = 0; + + fwrite(&bfh, 1, sizeof(bfh), fp); + fwrite(&bih, 1, sizeof(bih), fp); + + uint32 pitch = 4 * m_size.x; + uint8* data = (uint8*)image + (m_size.y - 1) * pitch; + + for(int h = m_size.y; h > 0; h--, data -= pitch) + { + fwrite(data, 1, m_size.x << 2, fp); // TODO: swap red-blue? + } + + fclose(fp); + + free(image); + return true; + } + + return false; #if 0 CComPtr res; diff --git a/plugins/GSdx/GSTextureOGL.h b/plugins/GSdx/GSTextureOGL.h index f2d66b3c8c..4e55225048 100644 --- a/plugins/GSdx/GSTextureOGL.h +++ b/plugins/GSdx/GSTextureOGL.h @@ -29,6 +29,8 @@ class GSTextureOGL : public GSTexture GLenum m_texture_target; // texture target: 2D, rectangle etc... 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; public: explicit GSTextureOGL(int type, int w, int h, bool msaa, int format); diff --git a/plugins/GSdx/GSVertex.h b/plugins/GSdx/GSVertex.h index 4daa85bdd5..111217148e 100644 --- a/plugins/GSdx/GSVertex.h +++ b/plugins/GSdx/GSVertex.h @@ -46,14 +46,10 @@ struct GSVertexP GSVector4 p; }; -struct GSVertexPT1 +__aligned(struct, 32) GSVertexPT1 { GSVector4 p; GSVector2 t; -#ifdef _LINUX - //FIXME aligment issue - GSVector2 pad; -#endif }; struct GSVertexPT2 diff --git a/plugins/GSdx/GSWnd.cpp b/plugins/GSdx/GSWnd.cpp index a9d67b989e..0ee8cce34a 100644 --- a/plugins/GSdx/GSWnd.cpp +++ b/plugins/GSdx/GSWnd.cpp @@ -314,6 +314,11 @@ void GSWnd::HideFrame() GSWnd::GSWnd() : m_window(NULL), m_Xwindow(0), m_XDisplay(NULL) { +#ifdef KEEP_SDL + m_renderer = 2; +#else + m_renderer = theApp.GetConfig("renderer", 0) / 3; +#endif } GSWnd::~GSWnd() @@ -334,6 +339,53 @@ bool GSWnd::Attach(void* handle, bool managed) m_Xwindow = *(Window*)handle; m_managed = managed; + if (m_renderer != 2) { + m_XDisplay = XOpenDisplay(NULL); + + // Get visual information + int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None + }; + + PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC) glXGetProcAddress((GLubyte *) "glXChooseFBConfig"); + int fbcount = 0; + 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"); + if (!glXCreateContextAttribsARB) return false; + + // Create a context + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + // FIXME : Request a debug context to ease opengl development + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, + 0 + }; + m_context = glXCreateContextAttribsARB(m_XDisplay, fbc[0], 0, true, context_attribs); + XSync( m_XDisplay, false); + + if (!m_context) return false; + glXMakeCurrent(m_XDisplay, m_Xwindow, m_context); + + // Check the status + int glxMajorVersion, glxMinorVersion; + glXQueryVersion(m_XDisplay, &glxMajorVersion, &glxMinorVersion); + if (glXIsDirect(m_XDisplay, m_context)) + fprintf(stderr, "glX-Version %d.%d with Direct Rendering\n", glxMajorVersion, glxMinorVersion); + else + fprintf(stderr, "glX-Version %d.%d with Indirect Rendering !!! It will be slow\n", glxMajorVersion, glxMinorVersion); + + } + + return true; } @@ -341,10 +393,15 @@ void GSWnd::Detach() { // Actually the destructor is not called when there is only a GSclose/GSshutdown // The window still need to be closed - if(m_window != NULL && m_managed) - { - SDL_DestroyWindow(m_window); - m_window = NULL; + if (m_renderer == 2) { + if(m_window != NULL && m_managed) + { + SDL_DestroyWindow(m_window); + m_window = NULL; + } + } else { + glXMakeCurrent(m_XDisplay, m_Xwindow, 0); + if (m_context) glXDestroyContext(m_XDisplay, m_context); } if (m_XDisplay) { XCloseDisplay(m_XDisplay); @@ -425,7 +482,8 @@ GSVector4i GSWnd::GetClientRect() // In real world...: if (!m_XDisplay) m_XDisplay = XOpenDisplay(NULL); XGetGeometry(m_XDisplay, m_Xwindow, &winDummy, &xDummy, &yDummy, &w, &h, &borderDummy, &depthDummy); - SDL_SetWindowSize(m_window, w, h); + if (m_renderer == 2) + SDL_SetWindowSize(m_window, w, h); return GSVector4i(0, 0, (int)w, (int)h); } @@ -445,23 +503,48 @@ bool GSWnd::SetWindowText(const char* title) // but we not use this function anyway. // FIXME: it does not feel a good solution -- Gregory // NOte: it might be more thread safe to use a call to XGetGeometry - SDL_PumpEvents(); int x,y = 0; - SDL_GetWindowPosition(m_window, &x, &y); - if ( x && y ) - SDL_SetWindowTitle(m_window, title); + if (m_renderer == 2) { + SDL_PumpEvents(); + SDL_GetWindowPosition(m_window, &x, &y); + if ( x && y ) + SDL_SetWindowTitle(m_window, title); + } return true; } +void GSWnd::Flip() +{ + if (m_renderer == 2) { +#if SDL_VERSION_ATLEAST(1,3,0) + SDL_GL_SwapWindow(m_window); +#else + SDL_GL_SwapBuffers(); +#endif + } else { + glXSwapBuffers(m_XDisplay, m_Xwindow); + } +} + void GSWnd::Show() { - SDL_ShowWindow(m_window); + if (m_renderer == 2) { + SDL_ShowWindow(m_window); + } else { + XMapRaised(m_XDisplay, m_Xwindow); + XFlush(m_XDisplay); + } } void GSWnd::Hide() { - SDL_HideWindow(m_window); + if (m_renderer == 2) { + SDL_HideWindow(m_window); + } else { + XUnmapWindow(m_XDisplay, m_Xwindow); + XFlush(m_XDisplay); + } } void GSWnd::HideFrame() diff --git a/plugins/GSdx/GSWnd.h b/plugins/GSdx/GSWnd.h index 9969638361..2c14b0794e 100644 --- a/plugins/GSdx/GSWnd.h +++ b/plugins/GSdx/GSWnd.h @@ -91,12 +91,16 @@ 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; Window m_Xwindow; Display* m_XDisplay; bool m_managed; + int m_renderer; + GLXContext m_context; public: GSWnd(); @@ -116,6 +120,7 @@ public: void Show(); void Hide(); void HideFrame(); + void Flip(); }; #endif diff --git a/plugins/GSdx/res/convert.glsl b/plugins/GSdx/res/convert.glsl index 33a1b1113a..861191a97b 100644 --- a/plugins/GSdx/res/convert.glsl +++ b/plugins/GSdx/res/convert.glsl @@ -2,6 +2,12 @@ #ifdef VERTEX_SHADER +out gl_PerVertex { + vec4 gl_Position; + float gl_PointSize; + float gl_ClipDistance[]; +}; + layout(location = 0) in vec4 POSITION; layout(location = 1) in vec2 TEXCOORD0; @@ -20,7 +26,7 @@ smooth layout(location = 1) out vec2 TEXCOORD0_OUT; void vs_main() { POSITION_OUT = POSITION; - TEXCOORD0_OUT = TEXCOORD0_OUT; + TEXCOORD0_OUT = TEXCOORD0; gl_Position = POSITION; // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position } @@ -32,7 +38,7 @@ void vs_main() layout(location = 0) in vec4 SV_Position; layout(location = 1) in vec2 TEXCOORD0; -out vec4 SV_Target0; +layout(location = 0) out vec4 SV_Target0; layout(binding = 0) uniform sampler2D TextureSampler; @@ -88,6 +94,21 @@ void ps_main6() // diagonal SV_Target0 = c; } +//void ps_main1() +//{ +// vec4 c = sample_c(TEXCOORD); +// +// c.a *= 256.0f / 127; // hm, 0.5 won't give us 1.0 if we just multiply with 2 +// +// uvec4 i = uvec4(c * vec4(0x001f, 0x03e0, 0x7c00, 0x8000)); +// +//#ifdef DEBUG_FRAG +// SV_Target0 = vec4(0.5,0.5,0.5,1.0); +//#else +// SV_Target0 = (i.x & 0x001f) | (i.y & 0x03e0) | (i.z & 0x7c00) | (i.w & 0x8000); +//#endif +//} + // Texture2D Texture; // SamplerState TextureSampler; // diff --git a/plugins/GSdx/res/interlace.glsl b/plugins/GSdx/res/interlace.glsl index 9933fe3b5e..5b04be378d 100644 --- a/plugins/GSdx/res/interlace.glsl +++ b/plugins/GSdx/res/interlace.glsl @@ -4,7 +4,7 @@ layout(location = 0) in vec4 SV_Position; layout(location = 1) in vec2 TEXCOORD0; -out vec4 SV_Target0; +layout(location = 0) out vec4 SV_Target0; layout(std140, binding = 1) uniform cb0 { diff --git a/plugins/GSdx/res/merge.glsl b/plugins/GSdx/res/merge.glsl index b46ac7d4ed..8f6ca11f09 100644 --- a/plugins/GSdx/res/merge.glsl +++ b/plugins/GSdx/res/merge.glsl @@ -1,11 +1,10 @@ //#version 420 // Keep it for editor detection #ifdef FRAGMENT_SHADER - layout(location = 0) in vec4 SV_Position; layout(location = 1) in vec2 TEXCOORD0; -out vec4 SV_Target0; +layout(location = 0) out vec4 SV_Target0; layout(std140, binding = 1) uniform cb0 { @@ -16,8 +15,9 @@ layout(binding = 0) uniform sampler2D TextureSampler; void ps_main0() { + vec4 c = texture(TextureSampler, TEXCOORD0); - c.a = min(c.a * 2, 1); + c.a = min(c.a * 2, 1.0); SV_Target0 = c; }