diff --git a/plugins/GSdx/CMakeLists.txt b/plugins/GSdx/CMakeLists.txt index 46254d9bc8..35bc667776 100644 --- a/plugins/GSdx/CMakeLists.txt +++ b/plugins/GSdx/CMakeLists.txt @@ -58,6 +58,7 @@ set(GSdxSources GSCodeBuffer.cpp GSCrc.cpp GSDevice.cpp + GSDeviceOGL.cpp GSDeviceSDL.cpp GSDeviceSW.cpp GSDeviceNull.cpp @@ -76,6 +77,7 @@ set(GSdxSources GSRasterizer.cpp GSRenderer.cpp GSRendererNull.cpp + GSRendererOGL.cpp GSRendererSW.cpp GSSetting.cpp GSSetupPrimCodeGenerator.cpp @@ -88,6 +90,8 @@ set(GSdxSources GSTexture.cpp GSTextureCache.cpp GSTextureCacheSW.cpp + GSTextureCacheOGL.cpp + GSTextureOGL.cpp GSTextureNull.cpp GSTextureSW.cpp GSThread.cpp @@ -123,6 +127,7 @@ set(GSdxHeaders GSCodeBuffer.h GSCrc.h GSDevice.h + GSDeviceOGL.h GSDeviceNull.h GSDirtyRect.h GSDrawScanline.h @@ -137,6 +142,8 @@ set(GSdxHeaders GSRenderer.h GSRendererNull.h GSRendererSW.h + GSRendererHW.h + GSRendererOGL.h GSScanlineEnvironment.h GSSetting.h GSSetupPrimCodeGenerator.h @@ -145,6 +152,7 @@ set(GSdxHeaders GSTexture.h GSTextureCache.h GSTextureCacheSW.h + GSTextureCacheOGL.h GSTextureNull.h GSThread.h GSUtil.h diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp index f3ccaf104b..d18be7fb2f 100644 --- a/plugins/GSdx/GS.cpp +++ b/plugins/GSdx/GS.cpp @@ -39,6 +39,9 @@ static HRESULT s_hr = E_FAIL; #else +#include "GSDeviceOGL.h" +#include "GSRendererOGL.h" + #include #include @@ -215,6 +218,7 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) #endif case 2: dev = new GSDeviceSDL(); break; case 3: dev = new GSDeviceNull(); break; + case 4: dev = new GSDeviceOGL(); break; } if(dev == NULL) @@ -227,11 +231,13 @@ static int _GSopen(void** dsp, char* title, int renderer, int threads = -1) switch(renderer % 3) { default: - #ifdef _WINDOWS case 0: + #ifdef _WINDOWS s_gs = (renderer / 3) == 0 ? (GSRenderer*)new GSRendererDX9() : (GSRenderer*)new GSRendererDX11(); - break; + #else + s_gs = (GSRenderer*)new GSRendererOGL(); #endif + break; case 1: s_gs = new GSRendererSW(threads); break; diff --git a/plugins/GSdx/GSDeviceOGL.cpp b/plugins/GSdx/GSDeviceOGL.cpp new file mode 100644 index 0000000000..576fe1d68e --- /dev/null +++ b/plugins/GSdx/GSDeviceOGL.cpp @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GSDeviceOGL.h" + +// Various Note: separate build of shader +// ************************** BUILD METHOD 1 +// 1/ create a stand alone prog +// uint CreateShaderProgramv( enum type, sizei count, const char **strings ); +// 2/ Create various prog pipeline (maybe 1 foreach combination or only 1) +// glGenProgramPipelines +// 3/ Attach a program to a pipeline +// void UseProgramStages( uint pipeline, bitfield stages, uint program ); +// ... +// ... +// 5/ Before the use of the program, we can validate it. (mandatory or not ?) +// glValidateProgramPipeline +// +// ************************** BUILD METHOD 2 +// Humm, there is another solutions. You can setup function pointer in GLSL and configure them with OPENGL. shader_subroutine. glUseProgram must be replace with glUseProgramInstance in this case (and instance must be managed) +//GL EXT: Overview +//GL EXT: +//GL EXT: This extension adds support to shaders for "indirect subroutine calls", +//GL EXT: where a single shader can include many subroutines and dynamically select +//GL EXT: through the API which subroutine is called from each call site. +//GL EXT: Switching subroutines dynamically in this fashion can avoid the cost of +//GL EXT: recompiling and managing multiple shaders, while still retaining most of +//GL EXT: the performance of specialized shaders. +// +// ************************** Uniform buffer +// // Note don't know how to chose block_binding_point (probably managed like texture unit +// maybe any number will be fine) +// index=glGetUniformBlockIndex(program, "BlockName"); +// glBindBufferBase(GL_UNIFORM_BUFFER, block_binding_point, some_buffer_object); +// glUniformBlockBinding(program, block_index, block_binding_point); + + +GSDeviceOGL::GSDeviceOGL() +{ + /* TODO */ + m_msaa = theApp.GetConfig("msaa", 0); +} + +GSDeviceOGL::~GSDeviceOGL() { /* TODO */ } + +GSTexture* GSDeviceOGL::CreateSurface(int type, int w, int h, bool msaa, int format) +{ + // A wrapper to call GSTextureOGL, with the different kind of parameter +} + +GSTexture* GSDeviceOGL::FetchSurface(int type, int w, int h, bool msaa, int format) +{ + // FIXME: keep DX code. Do not know how work msaa but not important for the moment +#if 0 + if(m_msaa < 2) { + msaa = false; + } +#endif + msaa = false; + + return GSDevice::FetchSurface(type, w, h, msaa, format); +} + +bool GSDeviceOGL::Create(GSWnd* wnd) +{ + /* TODO */ +} + +bool GSDeviceOGL::Reset(int w, int h) +{ + // Hum map, m_backbuffer to a GSTexture +} + +// Swap buffer (back buffer, front buffer) +// Warning it is not OGL dependent but application dependant (glx and so not portable) +void GSDeviceOGL::Flip() { /* TODO */ } + +// glDrawArrays +void GSDeviceOGL::DrawPrimitive() { /* TODO */ } + +// Just a wrapper around glClear* functions +void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c) { /* TODO */ } +void GSDeviceOGL::ClearRenderTarget(GSTexture* t, uint32 c) { /* TODO */ } +void GSDeviceOGL::ClearDepth(GSTexture* t, float c) { /* TODO */ } +void GSDeviceOGL::ClearStencil(GSTexture* t, uint8 c) { /* TODO */ } + +// the 4 next functions are only used to set some default value for the format. +// Need to find the default format... +// depth_stencil => GL_DEPTH32F_STENCIL8 +// others => (need 4* 8bits unsigned normalized integer) (GL_RGBA8 ) +GSTexture* GSDeviceOGL::CreateRenderTarget(int w, int h, bool msaa, int format) { /* TODO */ } +GSTexture* GSDeviceOGL::CreateDepthStencil(int w, int h, bool msaa, int format) { /* TODO */ } +GSTexture* GSDeviceOGL::CreateTexture(int w, int h, int format) { /* TODO */ } +GSTexture* GSDeviceOGL::CreateOffscreen(int w, int h, int format) { /* TODO */ } + +// blit a texture into an offscreen buffer +GSTexture* GSDeviceOGL::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format) +{ + // 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 != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT) + { + ASSERT(0); + + return false; + } + + if(GSTexture* rt = CreateRenderTarget(w, h, false, format)) + { + 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); + + if(src2 != src) Recycle(src2); + } + + dst = CreateOffscreen(w, h, format); + + if(dst) + { + m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt); + } + + Recycle(rt); + } + + return dst; +#endif +} + +// Copy a sub part of a texture into another +// Several question to answer did texture have same size? +// From a sub-part to the same sub-part +// From a sub-part to a full texture +void GSDeviceOGL::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r) +{ +#if 0 + if(!st || !dt) + { + ASSERT(0); + return; + } + + 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); +#endif +} + + +// Raster flow to resize a texture +// Note just call the StretchRect hardware accelerated +void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, int shader, bool linear) +{ + /* TODO */ +} +void GSDeviceOGL::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, GSUniformBufferOGL* ps_cb, bool linear) +{ + // TODO +} + +// 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 0 + if(!st || !dt) + { + ASSERT(0); + return; + } + + 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; + float right = dr.z * 2 / ds.x - 1.0f; + float bottom = 1.0f - dr.w * 2 / ds.y; + + 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)}, + {GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)}, + {GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)}, + }; + + IASetVertexBuffer(vertices, sizeof(vertices[0]), countof(vertices)); + IASetInputLayout(m_convert.il); + IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // vs + + VSSetShader(m_convert.vs, NULL); + + // gs + + GSSetShader(NULL); + + // ps + + PSSetShaderResources(st, NULL); + PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL); + PSSetShader(ps, ps_cb); + + // + + DrawPrimitive(); + + // + + EndScene(); + + PSSetShaderResources(NULL, NULL); +#endif +} + +void GSDeviceOGL::DoMerge(GSTexture* st[2], GSVector4* sr, GSTexture* dt, GSVector4* dr, bool slbg, bool mmod, const GSVector4& c) +{ +#if 0 + ClearRenderTarget(dt, c); + + if(st[1] && !slbg) + { + StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true); + } + + if(st[0]) + { + m_ctx->UpdateSubresource(m_merge.cb, 0, NULL, &c, 0, 0); + + StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], m_merge.cb, m_merge.bs, true); + } +#endif +} + +void GSDeviceOGL::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset) +{ +#if 0 + GSVector4 s = GSVector4(dt->GetSize()); + + GSVector4 sr(0, 0, 1, 1); + GSVector4 dr(0.0f, yoffset, s.x, s.y + yoffset); + + InterlaceConstantBuffer cb; + + cb.ZrH = GSVector2(0, 1.0f / s.y); + cb.hH = s.y / 2; + + m_ctx->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0); + + StretchRect(st, sr, dt, dr, m_interlace.ps[shader], m_interlace.cb, linear); +#endif +} + +// copy a multisample texture to a non-texture multisample. On opengl you need 2 FBO with different level of +// sample and then do a blit. Headach expected to for the moment just drop MSAA... +GSTexture* GSDeviceOGL::Resolve(GSTexture* t) +{ +#if 0 + ASSERT(t != NULL && t->IsMSAA()); + + if(GSTexture* dst = CreateRenderTarget(t->GetWidth(), t->GetHeight(), false, t->GetFormat())) + { + dst->SetScale(t->GetScale()); + + m_ctx->ResolveSubresource(*(GSTexture11*)dst, 0, *(GSTexture11*)t, 0, (DXGI_FORMAT)t->GetFormat()); + + return dst; + } + + return NULL; +#endif + return NULL; +} + +void GSDeviceOGL::IASetVertexBuffer(const void* vertices, size_t stride, size_t count) +{ + ASSERT(m_vertices.count == 0); + + if(count * stride > m_vertices.limit * m_vertices.stride) + { + // Current GPU buffer is too small need to realocate a new one +#if 0 + m_vb_old = m_vb; + m_vb = NULL; + + m_vertices.start = 0; + m_vertices.count = 0; + m_vertices.limit = std::max(count * 3 / 2, 11000); +#endif + } + + if(m_vb == NULL) + { + // Allocate a GPU buffer: GL_DYNAMIC_DRAW vs GL_STREAM_DRAW !!! + // glBufferData(GL_ARRAY_BUFFER, m_vertices.limit, NULL, GL_DYNAMIC_DRAW) +#if 0 + D3D11_BUFFER_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + bd.Usage = D3D11_USAGE_DYNAMIC; + bd.ByteWidth = m_vertices.limit * stride; + bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + HRESULT hr; + + hr = m_dev->CreateBuffer(&bd, NULL, &m_vb); + + if(FAILED(hr)) return; +#endif + } + + // append data or go back to the beginning + // Hum why we don't always go back to the beginning !!! +#if 0 + D3D11_MAP type = D3D11_MAP_WRITE_NO_OVERWRITE; + + if(m_vertices.start + count > m_vertices.limit || stride != m_vertices.stride) + { + m_vertices.start = 0; + + type = D3D11_MAP_WRITE_DISCARD; + } +#endif + + // Allocate the buffer + // glBufferSubData +#if 0 + D3D11_MAPPED_SUBRESOURCE m; + + if(SUCCEEDED(m_ctx->Map(m_vb, 0, type, 0, &m))) + { + GSVector4i::storent((uint8*)m.pData + m_vertices.start * stride, vertices, count * stride); + + m_ctx->Unmap(m_vb, 0); + } +#endif + + m_vertices.count = count; + m_vertices.stride = stride; + +// Useless ? +// binding of the buffer must be done anyway before glBufferSubData or glBufferData calls. +#if 0 + IASetVertexBuffer(m_vb, stride); +#endif +} + +// Useless ? +#if 0 +void GSDeviceOGL::IASetVertexBuffer(GLuint vb, size_t stride) +{ + if(m_state.vb != vb || m_state.vb_stride != stride) + { + m_state.vb = vb; + m_state.vb_stride = stride; + + uint32 stride2 = stride; + uint32 offset = 0; + + m_ctx->IASetVertexBuffers(0, 1, &vb, &stride2, &offset); + } +} +#endif + +// Useless ? +#if 0 +void GSDeviceOGL::IASetInputLayout(ID3D11InputLayout* layout) +{ + if(m_state.layout != layout) + { + m_state.layout = layout; + + m_ctx->IASetInputLayout(layout); + } +} +#endif + +// Useless ? +#if 0 +void GSDeviceOGL::IASetPrimitiveTopology(GLenum topology) +{ + if(m_state.topology != topology) + { + m_state.topology = topology; + + m_ctx->IASetPrimitiveTopology(topology); + } +} +#endif + +void GSDeviceOGL::VSSetShader(GLuint vs, GSUniformBufferOGL* vs_cb) +{ + // glUseProgramStage +#if 0 + if(m_state.vs != vs) + { + m_state.vs = vs; + + m_ctx->VSSetShader(vs, NULL, 0); + } +#endif + + // glBindBufferBase +#if 0 + if(m_state.vs_cb != vs_cb) + { + m_state.vs_cb = vs_cb; + + m_ctx->VSSetConstantBuffers(0, 1, &vs_cb); + } +#endif +} + +void GSDeviceOGL::GSSetShader(GLuint gs) +{ + // glUseProgramStage +#if 0 + if(m_state.gs != gs) + { + m_state.gs = gs; + + m_ctx->GSSetShader(gs, NULL, 0); + } +#endif +} + +void GSDeviceOGL::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1) +{ + PSSetShaderResource(0, sr0); + PSSetShaderResource(1, sr1); + PSSetShaderResource(2, NULL); +} + +void GSDeviceOGL::PSSetShaderResource(int i, GSTexture* sr) +{ +#if 0 + ID3D11ShaderResourceView* srv = NULL; + + if(sr) srv = *(GSTexture11*)sr; + + if(m_state.ps_srv[i] != srv) + { + m_state.ps_srv[i] = srv; + + m_srv_changed = true; + } +#endif +} + +void GSDeviceOGL::PSSetSamplerState(GLuint ss0, GLuint ss1, GLuint ss2) +{ +#if 0 + if(m_state.ps_ss[0] != ss0 || m_state.ps_ss[1] != ss1 || m_state.ps_ss[2] != ss2) + { + m_state.ps_ss[0] = ss0; + m_state.ps_ss[1] = ss1; + m_state.ps_ss[2] = ss2; + + m_ss_changed = true; + } +#endif +} + +void GSDeviceOGL::PSSetShader(GLuint ps, GSUniformBufferOGL* ps_cb) +{ + + // glUseProgramStage +#if 0 + if(m_state.ps != ps) + { + m_state.ps = ps; + + m_ctx->PSSetShader(ps, NULL, 0); + } +#endif + +// Sampler and texture must be set at the same time +// 1/ select the texture unit +// glActiveTexture(GL_TEXTURE0 + 1); +// 2/ bind the texture +// glBindTexture(GL_TEXTURE_2D , brickTexture); +// 3/ sets the texture sampler in GLSL (could be useless with layout stuff) +// glUniform1i(brickSamplerId , 1); +// 4/ set the sampler state +// glBindSampler(1 , sampler); +#if 0 + if (m_srv_changed) + { + m_ctx->PSSetShaderResources(0, 3, m_state.ps_srv); + + m_srv_changed = false; + } + + if(m_ss_changed) + { + m_ctx->PSSetSamplers(0, 3, m_state.ps_ss); + + m_ss_changed = false; + } +#endif + + // glBindBufferBase +#if 0 + if(m_state.ps_cb != ps_cb) + { + m_state.ps_cb = ps_cb; + + m_ctx->PSSetConstantBuffers(0, 1, &ps_cb); + } +#endif +} + +void GSDeviceOGL::OMSetDepthStencilState(GSDepthStencilOGL* dss, uint8 sref) +{ + // Setup the stencil object. sref can be set by glStencilFunc (note remove it from the structure) +#if 0 + if(m_state.dss != dss || m_state.sref != sref) + { + m_state.dss = dss; + m_state.sref = sref; + + m_ctx->OMSetDepthStencilState(dss, sref); + } +#endif +} + +void GSDeviceOGL::OMSetBlendState(GSBlendStateOGL* bs, float bf) +{ + // DX:Blend factor D3D11_BLEND_BLEND_FACTOR | D3D11_BLEND_INV_BLEND_FACTOR + // OPENGL: GL_CONSTANT_COLOR | GL_ONE_MINUS_CONSTANT_COLOR + // Note factor must be set before by glBlendColor +#if 0 + if(m_state.bs != bs || m_state.bf != bf) + { + m_state.bs = bs; + m_state.bf = bf; + + float BlendFactor[] = {bf, bf, bf, 0}; + + m_ctx->OMSetBlendState(bs, BlendFactor, 0xffffffff); + } +#endif +} + +void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor) +{ + // set the attachment inside the FBO + +#if 0 + ID3D11RenderTargetView* rtv = NULL; + ID3D11DepthStencilView* dsv = NULL; + + if(rt) rtv = *(GSTexture11*)rt; + if(ds) dsv = *(GSTexture11*)ds; + + if(m_state.rtv != rtv || m_state.dsv != dsv) + { + m_state.rtv = rtv; + m_state.dsv = dsv; + + m_ctx->OMSetRenderTargets(1, &rtv, dsv); + } +#endif + + // Viewport -> glViewport +#if 0 + if(m_state.viewport != rt->GetSize()) + { + m_state.viewport = rt->GetSize(); + + D3D11_VIEWPORT vp; + + memset(&vp, 0, sizeof(vp)); + + vp.TopLeftX = 0; + vp.TopLeftY = 0; + vp.Width = (float)rt->GetWidth(); + vp.Height = (float)rt->GetHeight(); + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + + m_ctx->RSSetViewports(1, &vp); + } +#endif + + // Scissor -> glScissor (note must be enabled) +#if 0 + GSVector4i r = scissor ? *scissor : GSVector4i(rt->GetSize()).zwxy(); + + if(!m_state.scissor.eq(r)) + { + m_state.scissor = r; + + m_ctx->RSSetScissorRects(1, r); + } +#endif +} diff --git a/plugins/GSdx/GSDeviceOGL.h b/plugins/GSdx/GSDeviceOGL.h new file mode 100644 index 0000000000..a18d2c3156 --- /dev/null +++ b/plugins/GSdx/GSDeviceOGL.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSDevice.h" +#include "GSTextureOGL.h" +#include "GSdx.h" + +struct GSBlendStateOGL { + // Note: You can also select the index of the draw buffer for which to set the blend setting + // We will keep basic the first try + bool m_enable; + GLenum m_equation_RGB; + GLenum m_equation_ALPHA; + GLenum m_func_RGB; + GLenum m_func_ALPHA; +}; + +struct GSDepthStencilOGL { + bool m_depth_enable; + GLenum m_depth_func; + // Note front face and back can be split might. But it seems they have same parameter configuration + bool m_stencil_enable; + GLuint m_stencil_mask; + GLuint m_stencil_func; + GLuint m_stencil_ref; + GLuint m_stencil_sfail_op; + GLuint m_stencil_spass_dfail_op; + GLuint m_stencil_spass_dpass_op; +}; + +struct GSUniformBufferOGL { + GLuint buffer; + GLuint index; +}; + +class GSDeviceOGL : public GSDevice +{ + uint32 m_msaa; + + // Vertex buffer: glGenBuffers, glBindBuffer GL_ARRAY_BUFFER + GLuint m_vb; // buffer object + + struct { + GLuint ps[2]; // program object + GSUniformBufferOGL* cb; // uniform buffer object + GSBlendStateOGL* bs; + } m_merge; + + struct { + GLuint ps[4]; // program object + GSUniformBufferOGL* cb; // uniform buffer object + } m_interlace; + + //struct + //{ + // CComPtr il; + // CComPtr vs; // program object + // CComPtr ps[8]; // program object + // CComPtr ln; + // CComPtr pt; + // CComPtr dss; + // CComPtr bs; // no equivalent + //} m_convert; + struct + { + // Hum I think this one is useless. As far as I understand + // it only get the index name of GLSL-equivalent input attribut + // ??? CComPtr il; + GLuint vs; // program object + GLuint ps[8]; // program object + GLuint ln; // sampler object + GLuint pt; // sampler object + GSDepthStencilOGL* dss; + GSBlendStateOGL* bs; + } m_convert; + + // struct + // { + // CComPtr dss; + // CComPtr bs; + // } m_date; + struct + { + GSDepthStencilOGL* dss; + GSBlendStateOGL* bs; + } m_date; + + // struct + // { + // ID3D11Buffer* vb; + // size_t vb_stride; + // ID3D11InputLayout* layout; + // D3D11_PRIMITIVE_TOPOLOGY topology; + // ID3D11VertexShader* vs; + // ID3D11Buffer* vs_cb; + // ID3D11GeometryShader* gs; + // ID3D11ShaderResourceView* ps_srv[3]; + // ID3D11PixelShader* ps; + // ID3D11Buffer* ps_cb; + // ID3D11SamplerState* ps_ss[3]; + // GSVector2i viewport; + // GSVector4i scissor; + // ID3D11DepthStencilState* dss; + // uint8 sref; + // ID3D11BlendState* bs; + // float bf; + // ID3D11RenderTargetView* rtv; + // ID3D11DepthStencilView* dsv; + // } m_state; + struct + { + GLuint vb; + // Hum I think those things can be dropped on OGL. It probably need an others architecture (see glVertexAttribPointer) + // size_t vb_stride; + // ID3D11InputLayout* layout; + GLenum topology; // (ie GL_TRIANGLES...) + GLuint vs; // program + GSUniformBufferOGL* vs_cb; // uniform buffer + GLuint gs; // program + // FIXME texture binding. Maybe not equivalent for the state but the best I could find. + GSTextureOGL* ps_srv[3]; + // ID3D11ShaderResourceView* ps_srv[3]; + GLuint ps; // program + GSUniformBufferOGL* ps_cb; // uniform buffer + GLuint ps_ss[3]; // sampler + GSVector2i viewport; + GSVector4i scissor; + GSDepthStencilOGL* dss; + uint8 sref; + GSBlendStateOGL* bs; + float bf; + // FIXME texture attachment in the FBO + // ID3D11RenderTargetView* rtv; + // ID3D11DepthStencilView* dsv; + } m_state; + + bool m_srv_changed; + bool m_ss_changed; + +#if 0 + CComPtr m_dev; + CComPtr m_ctx; + CComPtr m_swapchain; + + CComPtr m_rs; + + struct + { + CComPtr ps; + CComPtr cb; + } m_fxaa; + + + // Shaders... + + hash_map m_vs; + CComPtr m_vs_cb; + hash_map > m_gs; + hash_map > m_ps; + CComPtr m_ps_cb; + hash_map > m_ps_ss; + CComPtr m_palette_ss; + CComPtr m_rt_ss; + hash_map > m_om_dss; + hash_map > m_om_bs; + + VSConstantBuffer m_vs_cb_cache; + PSConstantBuffer m_ps_cb_cache; +#endif + + + protected: + GSTexture* CreateSurface(int type, int w, int h, bool msaa, int format); + GSTexture* FetchSurface(int type, int w, int h, bool msaa, int format); + void DoMerge(GSTexture* st[2], GSVector4* sr, GSTexture* dt, GSVector4* dr, bool slbg, bool mmod, const GSVector4& c); + void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0); + + public: + GSDeviceOGL(); + virtual ~GSDeviceOGL(); + + bool Create(GSWnd* wnd); + bool Reset(int w, int h); + void Flip(); + + void DrawPrimitive(); + + void ClearRenderTarget(GSTexture* t, const GSVector4& c); + void ClearRenderTarget(GSTexture* t, uint32 c); + void ClearDepth(GSTexture* t, float c); + void ClearStencil(GSTexture* t, uint8 c); + + GSTexture* CreateRenderTarget(int w, int h, bool msaa, int format = 0); + GSTexture* CreateDepthStencil(int w, int h, bool msaa, int format = 0); + GSTexture* CreateTexture(int w, int h, int format = 0); + GSTexture* CreateOffscreen(int w, int h, int format = 0); + + GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format = 0); + + void CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r); + void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, int shader = 0, bool linear = true); + void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, GSUniformBufferOGL* ps_cb, bool linear); + void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, GLuint ps, GSUniformBufferOGL ps_cb, GSBlendStateOGL* bs, bool linear); + + GSTexture* Resolve(GSTexture* t); + + void IASetVertexBuffer(const void* vertices, size_t stride, size_t count); + + void VSSetShader(GLuint vs, GSUniformBufferOGL* vs_cb); + void GSSetShader(GLuint gs); + + void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1); + void PSSetShaderResource(int i, GSTexture* sr); + void PSSetSamplerState(GLuint ss0, GLuint ss1, GLuint ss2); + void PSSetShader(GLuint ps, GSUniformBufferOGL* ps_cb); + + void OMSetDepthStencilState(GSDepthStencilOGL* dss, uint8 sref); + void OMSetBlendState(GSBlendStateOGL* bs, float bf); + void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL); + + +}; diff --git a/plugins/GSdx/GSLinuxDialog.cpp b/plugins/GSdx/GSLinuxDialog.cpp index 271b8e2619..7384a76a2a 100644 --- a/plugins/GSdx/GSLinuxDialog.cpp +++ b/plugins/GSdx/GSLinuxDialog.cpp @@ -42,6 +42,7 @@ static void SysMessage(const char *fmt, ...) bool RunLinuxDialog() { + // FIXME need to add msaa option configuration GtkWidget *dialog; GtkWidget *main_frame, *main_box; GtkWidget *render_label, *render_combo_box; @@ -76,10 +77,25 @@ bool RunLinuxDialog() if(!s.note.empty()) label += format(" (%s)", s.note.c_str()); + // (dev only) for any NULL stuff + if (i >= 7 && i <= 9) label += " (debug only)"; + // (experimental) for opengl stuff + if (i == 10 || i == 11) label += " (experimental)"; + gtk_combo_box_append_text(GTK_COMBO_BOX(render_combo_box), label.c_str()); } - gtk_combo_box_set_active(GTK_COMBO_BOX(render_combo_box), 0); + int renderer_box_position = 0; + switch (theApp.GetConfig("renderer", 0)) { + // Note the value are based on m_gs_renderers vector on GSdx.cpp + case 7 : renderer_box_position = 0; break; + case 8 : renderer_box_position = 1; break; + case 10: renderer_box_position = 2; break; + case 11: renderer_box_position = 3; break; + case 12: renderer_box_position = 4; break; + case 13: renderer_box_position = 5; break; + } + gtk_combo_box_set_active(GTK_COMBO_BOX(render_combo_box), renderer_box_position ); gtk_container_add(GTK_CONTAINER(main_box), render_label); gtk_container_add(GTK_CONTAINER(main_box), render_combo_box); @@ -142,12 +158,22 @@ bool RunLinuxDialog() if (return_value == GTK_RESPONSE_ACCEPT) { // Get all the settings from the dialog box. + if (gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box)) != -1) { + // FIXME test current opengl version supported through glxinfo (OpenGL version string:) + // Warn the user if 4.2 is not supported and switch back to basic SDL renderer + switch (gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box))) { + // Note the value are based on m_gs_renderers vector on GSdx.cpp + case 0: theApp.SetConfig("renderer", 7); break; + case 1: theApp.SetConfig("renderer", 8); break; + case 2: theApp.SetConfig("renderer", 10); break; + case 3: theApp.SetConfig("renderer", 11); break; + case 4: theApp.SetConfig("renderer", 12); break; + case 5: theApp.SetConfig("renderer", 13); break; + } + } #if 0 // I'll put the right variable names in later. - if (gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box)) != -1) - renderer = gtk_combo_box_get_active(GTK_COMBO_BOX(render_combo_box)); - // Crash, for some interlace options if (gtk_combo_box_get_active(GTK_COMBO_BOX(interlace_combo_box)) != -1) theApp.SetConfig( "interlace", (int)gtk_combo_box_get_active(GTK_COMBO_BOX(interlace_combo_box)) ); diff --git a/plugins/GSdx/GSRendererOGL.cpp b/plugins/GSdx/GSRendererOGL.cpp new file mode 100644 index 0000000000..df1474c6d2 --- /dev/null +++ b/plugins/GSdx/GSRendererOGL.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GSRendererOGL.h" +#include "GSRenderer.h" + + +GSRendererOGL::GSRendererOGL() + // FIXME + //: GSRendererHW(new GSTextureCacheOGL(this)) + : GSRendererHW(new GSTextureCacheOGL(this)) +{ + // TODO must be implementer with macro InitVertexKick(GSRendererOGL) + // template void VertexKick(bool skip); + InitVertexKick(GSRendererOGL); +} + +GSRendererOGL::~GSRendererOGL() { /* TODO */ } + +bool GSRendererOGL::CreateDevice(GSDevice* dev) { /* TODO */ } + +template +void GSRendererOGL::VertexKick(bool skip) { /* TODO */ } + +void GSRendererOGL::Draw(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex) { /* TODO */ } diff --git a/plugins/GSdx/GSRendererOGL.h b/plugins/GSdx/GSRendererOGL.h new file mode 100644 index 0000000000..0c75556a7f --- /dev/null +++ b/plugins/GSdx/GSRendererOGL.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSRendererHW.h" + +#include "GSRenderer.h" +#include "GSTextureCacheOGL.h" +#include "GSVertexHW.h" + +// FIXME does it need a GSVertexHWOGL ??? Data order can be easily programmed on opengl (the only potential +// issue is the unsupported praga push/pop +// Note it impact GSVertexTrace.cpp => void GSVertexTrace::Update(const GSVertexHWOGL* v, int count, GS_PRIM_CLASS primclass) +class GSRendererOGL : public GSRendererHW +//class GSRendererOGL : public GSRendererHW +{ + private: + + protected: + GSTextureCache* m_tc; + + void Draw(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex); + + public: + GSRendererOGL(); + virtual ~GSRendererOGL(); + + template void VertexKick(bool skip); + + bool CreateDevice(GSDevice* dev); +}; diff --git a/plugins/GSdx/GSSetting.h b/plugins/GSdx/GSSetting.h index 503b535bb8..1f8264c771 100644 --- a/plugins/GSdx/GSSetting.h +++ b/plugins/GSdx/GSSetting.h @@ -21,6 +21,8 @@ #pragma once +#include "stdafx.h" + struct GSSetting { uint32 id; diff --git a/plugins/GSdx/GSTextureCacheOGL.cpp b/plugins/GSdx/GSTextureCacheOGL.cpp new file mode 100644 index 0000000000..5b4605a2c3 --- /dev/null +++ b/plugins/GSdx/GSTextureCacheOGL.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "stdafx.h" +#include "GSTextureCacheOGL.h" + +GSTextureCacheOGL::GSTextureCacheOGL(GSRenderer* r) + : GSTextureCache(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 + + return; + } + + const GIFRegTEX0& TEX0 = t->m_TEX0; + + if(TEX0.PSM != PSM_PSMCT32 + && TEX0.PSM != PSM_PSMCT24 + && TEX0.PSM != PSM_PSMCT16 + && TEX0.PSM != PSM_PSMCT16S) + { + //ASSERT(0); + + return; + } + + if(!t->m_dirty.empty()) + { + return; + } + + // printf("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n", r.left, r.top, r.right, r.bottom, TEX0.TBP0); + + int w = r.width(); + int h = r.height(); + + GSVector4 src = GSVector4(r) * GSVector4(t->m_texture->GetScale()).xyxy() / GSVector4(t->m_texture->GetSize()).xyxy(); + + DXGI_FORMAT format = TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; + + if(GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(t->m_texture, src, w, h, format)) + { + GSTexture::GSMap m; + + if(offscreen->Map(m)) + { + // TODO: block level write + + GSOffset* o = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM); + + switch(TEX0.PSM) + { + case PSM_PSMCT32: + m_renderer->m_mem.WritePixel32(m.bits, m.pitch, o, r); + break; + case PSM_PSMCT24: + m_renderer->m_mem.WritePixel24(m.bits, m.pitch, o, r); + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + m_renderer->m_mem.WritePixel16(m.bits, m.pitch, o, r); + break; + default: + ASSERT(0); + } + + offscreen->Unmap(); + } + + m_renderer->m_dev->Recycle(offscreen); + } +#endif +} + diff --git a/plugins/GSdx/GSTextureCacheOGL.h b/plugins/GSdx/GSTextureCacheOGL.h new file mode 100644 index 0000000000..11bf6210ad --- /dev/null +++ b/plugins/GSdx/GSTextureCacheOGL.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * http://www.gabest.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTextureCache.h" +#include "GSDeviceOGL.h" + +class GSTextureCacheOGL : public GSTextureCache +{ +protected: + int Get8bitFormat() {/* TODO return DXGI_FORMAT_A8_UNORM;*/} + + void Read(Target* t, const GSVector4i& r); + +public: + GSTextureCacheOGL(GSRenderer* r); +}; diff --git a/plugins/GSdx/GSTextureOGL.cpp b/plugins/GSdx/GSTextureOGL.cpp new file mode 100644 index 0000000000..d1b0eb5912 --- /dev/null +++ b/plugins/GSdx/GSTextureOGL.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTextureOGL.h" + +GSTextureOGL::GSTextureOGL(/* ID3D11Texture2D* texture */ ) +{ + // ************************************************************* + // Opengl world + + // http://www.opengl.org/wiki/Renderbuffer_Object + // render: constructor -> glGenRenderbuffers, glDeleteRenderbuffers + // info -> glGetRenderbufferParameteriv, glIsRenderbuffer + // binding -> glBindRenderbuffer (only 1 target), glFramebufferRenderbuffer (attach actually) + // setup param -> glRenderbufferStorageMultisample (after this call the buffer is unitialized) + // + // the only way to use a renderbuffer object is to attach it to a Framebuffer Object. After you bind that + // FBO to the context, and set up the draw or read buffers appropriately, you can use pixel transfer operations + // to read and write to it. Of course, you can also render to it. The standard glClear function will also clear the appropriate buffer. + // + // Render work in parallal with framebuffer object (FBO) http://www.opengl.org/wiki/Framebuffer_Objects + // render are attached to FBO through : glFramebufferRenderbuffer. You can query the number of colorattachement with GL_MAX_COLOR_ATTACHMENTS + // FBO : constructor -> glGenFramebuffers, glDeleteFramebuffers + // binding -> glBindFramebuffer (target can be read/write/both) + // blit -> glBlitFramebuffer (read FB to draw FB) + // info -> glIsFramebuffer, glGetFramebufferAttachmentParameter, glCheckFramebufferStatus + // + // There are two types of framebuffer-attachable images; texture images and renderbuffer images. + // If an image of a texture object is attached to a framebuffer, OpenGL performs "render to texture". + // And if an image of a renderbuffer object is attached to a framebuffer, then OpenGL performs "offscreen rendering". + // Blitting: + // glDrawBuffers + // glReadBuffer + // glBlitFramebuffer + + // ************************************************************* + // Doc + // It might need a texture structure to replace ID3D11Texture2D. + // + // == The function need to set (from parameter) + // : m_size.x + // : m_size.y + // : m_type + // : m_format + // : m_msaa + // == Might be useful to save + // : m_texture_target (like GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE etc...) + // : m_texture_id (return by glGen*) + // + // == Then generate the texture or buffer. + // D3D11_BIND_RENDER_TARGET: Bind a texture as a render target for the output-merger stage. + // => glGenRenderbuffers with GL_COLOR_ATTACHMENTi (Hum glGenTextures might work too) + // D3D11_BIND_DEPTH_STENCIL: Bind a texture as a depth-stencil target for the output-merger stage. + // => glGenRenderbuffers with GL_DEPTH_STENCIL_ATTACHMENT + // D3D11_BIND_SHADER_RESOURCE: Bind a buffer or texture to a shader stage + // => glGenTextures + // D3D11_USAGE_STAGING: A resource that supports data transfer (copy) from the GPU to the CPU. + // glGenTextures + // glReadPixels seems to use a framebuffer. In this case you can setup the source + // with glReadBuffer(GL_COLOR_ATTACHMENTi) + // glGetTexImage: read pixels of a bound texture + // => To allow map/unmap. I think we can use a pixel buffer (target GL_PIXEL_UNPACK_BUFFER) + // http://www.opengl.org/wiki/Pixel_Buffer_Objects + // == Enable texture Unit + // EnableUnit(); + // == Allocate space + // glRenderbufferStorageMultisample or glTexStorage2D + + +#if 0 + m_texture->GetDevice(&m_dev); + m_texture->GetDesc(&m_desc); + + m_dev->GetImmediateContext(&m_ctx); + + m_size.x = (int)m_desc.Width; + m_size.y = (int)m_desc.Height; + + if(m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) m_type = RenderTarget; + else if(m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) m_type = DepthStencil; + else if(m_desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) m_type = Texture; + else if(m_desc.Usage == D3D11_USAGE_STAGING) m_type = Offscreen; + + m_format = (int)m_desc.Format; + + m_msaa = m_desc.SampleDesc.Count > 1; +#endif +} + +GSTextureOGL::~GSTextureOGL() +{ + // glDeleteTextures or glDeleteRenderbuffers +} + +void GSTextureOGL::EnableUnit() +{ + // == For texture, the Unit must be selected + // glActiveTexture + // !!!!!!!!!! VERY BIG ISSUE, how to ensure that the different texture use different texture unit. + // I think we need to create a pool on GSdevice. + // 1/ this->m_device_ogl + // 2/ int GSDeviceOGL::get_free_texture_unit() called from GSTextureOGL constructor + // 3/ void GSDeviceOGL::release_texture_unit(int) called from GSDeviceOGL destructor + // Another (better) idea, will be to create a global static pool + // + // == Bind the texture or buffer + // glBindRenderbuffer or glBindTexture + // + // !!!!!!!!!! Maybe attach to the FBO but where to manage the FBO!!! + // Create a separare public method for attachment ??? +} + +bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch) +{ + // To update only a part of the texture you can use: + // glTexSubImage2D — specify a two-dimensional texture subimage +#if 0 + if(m_dev && m_texture) + { + D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; + + m_ctx->UpdateSubresource(m_texture, 0, &box, data, pitch, 0); + + return true; + } + + return false; +#endif +} + +bool GSTextureOGL::Map(GSMap& m, const GSVector4i* r) +{ + // The function allow to modify the texture from the CPU + // Set m.bits <- pointer to the data + // Set m.pitch <- size of a row + // I think in opengl we need to copy back the data to the RAM: glReadPixels — read a block of pixels from the frame buffer + // + // glMapBuffer — map a buffer object's data store +#if 0 + if(r != NULL) + { + // ASSERT(0); // not implemented + + return false; + } + + if(m_texture && m_desc.Usage == D3D11_USAGE_STAGING) + { + D3D11_MAPPED_SUBRESOURCE map; + + if(SUCCEEDED(m_ctx->Map(m_texture, 0, D3D11_MAP_READ_WRITE, 0, &map))) + { + m.bits = (uint8*)map.pData; + m.pitch = (int)map.RowPitch; + + return true; + } + } + + return false; +#endif +} + +void GSTextureOGL::Unmap() +{ + // copy the texture to the GPU + // GLboolean glUnmapBuffer(GLenum target); +#if 0 + if(m_texture) + { + m_ctx->Unmap(m_texture, 0); + } +#endif +} + +// If I'm correct, this function only dump some buffer. Debug only, still very useful! +// Note: check zzogl implementation +bool GSTextureOGL::Save(const string& fn, bool dds) +{ +#if 0 + CComPtr res; + + if(m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) + { + HRESULT hr; + + D3D11_TEXTURE2D_DESC desc; + + memset(&desc, 0, sizeof(desc)); + + m_texture->GetDesc(&desc); + + desc.Usage = D3D11_USAGE_STAGING; + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + + CComPtr src, dst; + + hr = m_dev->CreateTexture2D(&desc, NULL, &src); + + m_ctx->CopyResource(src, m_texture); + + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + hr = m_dev->CreateTexture2D(&desc, NULL, &dst); + + D3D11_MAPPED_SUBRESOURCE sm, dm; + + hr = m_ctx->Map(src, 0, D3D11_MAP_READ, 0, &sm); + hr = m_ctx->Map(dst, 0, D3D11_MAP_WRITE, 0, &dm); + + uint8* s = (uint8*)sm.pData; + uint8* d = (uint8*)dm.pData; + + for(uint32 y = 0; y < desc.Height; y++, s += sm.RowPitch, d += dm.RowPitch) + { + for(uint32 x = 0; x < desc.Width; x++) + { + ((uint32*)d)[x] = (uint32)(ldexpf(((float*)s)[x*2], 32)); + } + } + + m_ctx->Unmap(src, 0); + m_ctx->Unmap(dst, 0); + + res = dst; + } + else + { + res = m_texture; + } + + return SUCCEEDED(D3DX11SaveTextureToFile(m_ctx, res, dds ? D3DX11_IFF_DDS : D3DX11_IFF_BMP, fn.c_str())); +#endif +} + diff --git a/plugins/GSdx/GSTextureOGL.h b/plugins/GSdx/GSTextureOGL.h new file mode 100644 index 0000000000..6df0d212dc --- /dev/null +++ b/plugins/GSdx/GSTextureOGL.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011-2011 Gregory hainaut + * Copyright (C) 2007-2009 Gabest + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#pragma once + +#include "GSTexture.h" + +class GSTextureOGL : public GSTexture +{ + private: + GLenum m_texture_target; // texture target: 2D, rectangle etc... + GLuint m_texture_id; // the texture id + int m_texture_unit; // the texture unit offset + + void EnableUnit(); + + public: + explicit GSTextureOGL(); + virtual ~GSTextureOGL(); + + bool Update(const GSVector4i& r, const void* data, int pitch); + bool Map(GSMap& m, const GSVector4i* r = NULL); + void Unmap(); + bool Save(const string& fn, bool dds = false); +}; diff --git a/plugins/GSdx/GSVertexList.h b/plugins/GSdx/GSVertexList.h index adc6efda1d..e300ab88f1 100644 --- a/plugins/GSdx/GSVertexList.h +++ b/plugins/GSdx/GSVertexList.h @@ -33,7 +33,7 @@ public: { m_base = _aligned_malloc(sizeof(Vertex) * countof(m_v), 32); - for(int i = 0; i < countof(m_v); i++) + for(uint i = 0; i < countof(m_v); i++) { m_v[i] = &((Vertex*)m_base)[i]; } diff --git a/plugins/GSdx/GSWnd.cpp b/plugins/GSdx/GSWnd.cpp index 02afc92ad7..b306932a51 100644 --- a/plugins/GSdx/GSWnd.cpp +++ b/plugins/GSdx/GSWnd.cpp @@ -376,6 +376,22 @@ bool GSWnd::Create(const string& title, int w, int h) #endif m_managed = true; + + // If the user request OpenGL acceleration, we take recent OGL version (4.2) + // We keep the default 2.1 version in SW mode (only DX11 capable card, are compatible with OGL4) + if ( theApp.GetConfig("renderer", 0) / 3 == 4 ) { + // Setup visual attribute + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 ); + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 32 ); + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ); + // Ask for an advance opengl version + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 ); + SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 2 ); + } + m_window = SDL_CreateWindow(title.c_str(), 100, 100, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); // Get the X window from the newly created window diff --git a/plugins/GSdx/GSdx.cpp b/plugins/GSdx/GSdx.cpp index 88885b0a0d..f518d666c1 100644 --- a/plugins/GSdx/GSdx.cpp +++ b/plugins/GSdx/GSdx.cpp @@ -116,6 +116,8 @@ GSdxApp::GSdxApp() m_gs_renderers.push_back(GSSetting(8, "SDL 1.3", "Null")); m_gs_renderers.push_back(GSSetting(10, "Null", "Software")); m_gs_renderers.push_back(GSSetting(11, "Null", "Null")); + m_gs_renderers.push_back(GSSetting(12, "OpenGL", "Hardware")); + m_gs_renderers.push_back(GSSetting(13, "OpenGL", "Software")); m_gs_interlace.push_back(GSSetting(0, "None", "")); m_gs_interlace.push_back(GSSetting(1, "Weave tff", "saw-tooth")); diff --git a/plugins/GSdx/stdafx.h b/plugins/GSdx/stdafx.h index cc28f6ca91..0fb788ba93 100644 --- a/plugins/GSdx/stdafx.h +++ b/plugins/GSdx/stdafx.h @@ -111,6 +111,10 @@ using namespace stdext; //#include //#include +#include +#include +#include + //using namespace __gnu_cxx; #define DIRECTORY_SEPARATOR '/' @@ -333,4 +337,4 @@ extern void vmfree(void* ptr, size_t size); //#define NO_CRC_HACKS // Disable all game specific hacks #ifdef HW_NO_TEXTURE_CACHE #define NO_CRC_HACKS -#endif \ No newline at end of file +#endif