diff --git a/plugins/GSdx/GSDevice11.cpp b/plugins/GSdx/GSDevice11.cpp new file mode 100644 index 0000000000..c31c0a8d92 --- /dev/null +++ b/plugins/GSdx/GSDevice11.cpp @@ -0,0 +1,870 @@ +/* + * 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 "GSdx.h" +#include "GSDevice11.h" +#include "resource.h" + +GSDevice11::GSDevice11() + : m_vb(NULL) + , m_vb_stride(0) + , m_layout(NULL) + , m_topology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED) + , m_vs(NULL) + , m_vs_cb(NULL) + , m_gs(NULL) + , m_ps(NULL) + , m_ps_cb(NULL) + , m_scissor(0, 0, 0, 0) + , m_viewport(0, 0) + , m_dss(NULL) + , m_sref(0) + , m_bs(NULL) + , m_bf(-1) + , m_rtv(NULL) + , m_dsv(NULL) +{ + memset(m_ps_srv, 0, sizeof(m_ps_srv)); + memset(m_ps_ss, 0, sizeof(m_ps_ss)); + + m_vertices.stride = 0; + m_vertices.start = 0; + m_vertices.count = 0; + m_vertices.limit = 0; +} + +GSDevice11::~GSDevice11() +{ +} + +bool GSDevice11::Create(GSWnd* wnd, bool vsync) +{ + if(!__super::Create(wnd, vsync)) + { + return false; + } + + HRESULT hr; + + DXGI_SWAP_CHAIN_DESC scd; + D3D11_BUFFER_DESC bd; + D3D11_SAMPLER_DESC sd; + D3D11_DEPTH_STENCIL_DESC dsd; + D3D11_RASTERIZER_DESC rd; + D3D11_BLEND_DESC bsd; + + memset(&scd, 0, sizeof(scd)); + + scd.BufferCount = 2; + scd.BufferDesc.Width = 1; + scd.BufferDesc.Height = 1; + scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + //scd.BufferDesc.RefreshRate.Numerator = 60; + //scd.BufferDesc.RefreshRate.Denominator = 1; + scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + scd.OutputWindow = (HWND)m_wnd->GetHandle(); + scd.SampleDesc.Count = 1; + scd.SampleDesc.Quality = 0; + scd.Windowed = TRUE; + + uint32 flags = 0; + +#ifdef DEBUG + flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &m_level, &m_ctx); + // hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &m_level, &m_ctx); + + if(FAILED(hr)) return false; + + D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS options; + + hr = m_dev->CheckFeatureSupport(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, &options, sizeof(D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS)); + + switch(m_level) + { + case D3D_FEATURE_LEVEL_9_1: + case D3D_FEATURE_LEVEL_9_2: + m_shader.model = "0x200"; + m_shader.vs = "vs_4_0_level_9_1"; + m_shader.ps = "ps_4_0_level_9_1"; + break; + case D3D_FEATURE_LEVEL_9_3: + m_shader.model = "0x300"; + m_shader.vs = "vs_4_0_level_9_3"; + m_shader.ps = "ps_4_0_level_9_3"; + break; + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + m_shader.model = "0x400"; + m_shader.vs = "vs_4_0"; + m_shader.gs = "gs_4_0"; + m_shader.ps = "ps_4_0"; + break; + case D3D_FEATURE_LEVEL_11_0: + m_shader.model = "0x500"; + m_shader.vs = "vs_5_0"; + m_shader.gs = "gs_5_0"; + m_shader.ps = "ps_5_0"; + break; + } + + if(m_level < D3D_FEATURE_LEVEL_10_0) + { + return false; + } + + // convert + + D3D11_INPUT_ELEMENT_DESC il_convert[] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + hr = CompileShader(IDR_CONVERT_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il); + + for(int i = 0; i < countof(m_convert.ps); i++) + { + hr = CompileShader(IDR_CONVERT_FX, format("ps_main%d", i), NULL, &m_convert.ps[i]); + } + + memset(&dsd, 0, sizeof(dsd)); + + dsd.DepthEnable = false; + dsd.StencilEnable = false; + + hr = m_dev->CreateDepthStencilState(&dsd, &m_convert.dss); + + memset(&bsd, 0, sizeof(bsd)); + + bsd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + hr = m_dev->CreateBlendState(&bsd, &m_convert.bs); + + // merge + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(MergeConstantBuffer); + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + hr = m_dev->CreateBuffer(&bd, NULL, &m_merge.cb); + + for(int i = 0; i < countof(m_merge.ps); i++) + { + hr = CompileShader(IDR_MERGE_FX, format("ps_main%d", i), NULL, &m_merge.ps[i]); + } + + memset(&bsd, 0, sizeof(bsd)); + + bsd.RenderTarget[0].BlendEnable = true; + bsd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + bsd.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + bsd.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + bsd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + bsd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + bsd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + bsd.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + hr = m_dev->CreateBlendState(&bsd, &m_merge.bs); + + // interlace + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(InterlaceConstantBuffer); + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + hr = m_dev->CreateBuffer(&bd, NULL, &m_interlace.cb); + + for(int i = 0; i < countof(m_interlace.ps); i++) + { + hr = CompileShader(IDR_INTERLACE_FX, format("ps_main%d", i), NULL, &m_interlace.ps[i]); + } + + // + + memset(&rd, 0, sizeof(rd)); + + rd.FillMode = D3D11_FILL_SOLID; + rd.CullMode = D3D11_CULL_NONE; + rd.FrontCounterClockwise = false; + rd.DepthBias = false; + rd.DepthBiasClamp = 0; + rd.SlopeScaledDepthBias = 0; + rd.DepthClipEnable = false; // ??? + rd.ScissorEnable = true; + rd.MultisampleEnable = false; + rd.AntialiasedLineEnable = false; + + hr = m_dev->CreateRasterizerState(&rd, &m_rs); + + m_ctx->RSSetState(m_rs); + + // + + memset(&sd, 0, sizeof(sd)); + + sd.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sd.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.MaxLOD = FLT_MAX; + sd.MaxAnisotropy = 16; + sd.ComparisonFunc = D3D11_COMPARISON_NEVER; + + hr = m_dev->CreateSamplerState(&sd, &m_convert.ln); + + sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + + hr = m_dev->CreateSamplerState(&sd, &m_convert.pt); + + // + + Reset(1, 1, false); + + // + + return true; +} + +bool GSDevice11::Reset(int w, int h, bool fs) +{ + if(!__super::Reset(w, h, fs)) + return false; + + DXGI_SWAP_CHAIN_DESC scd; + memset(&scd, 0, sizeof(scd)); + m_swapchain->GetDesc(&scd); + m_swapchain->ResizeBuffers(scd.BufferCount, w, h, scd.BufferDesc.Format, 0); + + CComPtr backbuffer; + m_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backbuffer); + m_backbuffer = new GSTexture11(backbuffer); + + return true; +} + +void GSDevice11::Flip() +{ + m_swapchain->Present(m_vsync ? 1 : 0, 0); +} + +void GSDevice11::BeginScene() +{ +} + +void GSDevice11::DrawPrimitive() +{ + m_ctx->Draw(m_vertices.count, m_vertices.start); +} + +void GSDevice11::EndScene() +{ + PSSetShaderResources(NULL, NULL); + + // not clearing the rt/ds gives a little fps boost in complex games (5-10%) + + // OMSetRenderTargets(NULL, NULL); + + m_vertices.start += m_vertices.count; + m_vertices.count = 0; +} + +void GSDevice11::ClearRenderTarget(GSTexture* t, const GSVector4& c) +{ + m_ctx->ClearRenderTargetView(*(GSTexture11*)t, c.v); +} + +void GSDevice11::ClearRenderTarget(GSTexture* t, uint32 c) +{ + GSVector4 color = GSVector4(c) * (1.0f / 255); + + m_ctx->ClearRenderTargetView(*(GSTexture11*)t, color.v); +} + +void GSDevice11::ClearDepth(GSTexture* t, float c) +{ + m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_DEPTH, c, 0); +} + +void GSDevice11::ClearStencil(GSTexture* t, uint8 c) +{ + m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_STENCIL, 0, c); +} + +GSTexture* GSDevice11::Create(int type, int w, int h, int format) +{ + HRESULT hr; + + D3D11_TEXTURE2D_DESC desc; + + memset(&desc, 0, sizeof(desc)); + + desc.Width = w; + desc.Height = h; + desc.Format = (DXGI_FORMAT)format; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + + switch(type) + { + case GSTexture::RenderTarget: + desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + break; + case GSTexture::DepthStencil: + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + break; + case GSTexture::Texture: + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + break; + case GSTexture::Offscreen: + desc.Usage = D3D11_USAGE_STAGING; + desc.CPUAccessFlags |= D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + break; + } + + GSTexture11* t = NULL; + + CComPtr texture; + + hr = m_dev->CreateTexture2D(&desc, NULL, &texture); + + if(SUCCEEDED(hr)) + { + t = new GSTexture11(texture); + + switch(type) + { + case GSTexture::RenderTarget: + ClearRenderTarget(t, 0); + break; + case GSTexture::DepthStencil: + ClearDepth(t, 0); + break; + } + } + + return t; +} + +GSTexture* GSDevice11::CreateRenderTarget(int w, int h, int format) +{ + return __super::CreateRenderTarget(w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +GSTexture* GSDevice11::CreateDepthStencil(int w, int h, int format) +{ + return __super::CreateDepthStencil(w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT); +} + +GSTexture* GSDevice11::CreateTexture(int w, int h, int format) +{ + return __super::CreateTexture(w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +GSTexture* GSDevice11::CreateOffscreen(int w, int h, int format) +{ + return __super::CreateOffscreen(w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +GSTexture* GSDevice11::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format) +{ + 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, format)) + { + GSVector4 dr(0, 0, w, h); + + StretchRect(src, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL); + + dst = CreateOffscreen(w, h, format); + + if(dst) + { + m_ctx->CopyResource(*(GSTexture11*)dst, *(GSTexture11*)rt); + } + + Recycle(rt); + } + + return dst; +} + +void GSDevice11::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, int shader, bool linear) +{ + StretchRect(st, sr, dt, dr, m_convert.ps[shader], NULL, linear); +} + +void GSDevice11::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear) +{ + StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear); +} + +void GSDevice11::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear) +{ + 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 + + PSSetShader(ps, ps_cb); + PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL); + PSSetShaderResources(st, NULL); + + // rs + + RSSet(ds.x, ds.y); + + // + + DrawPrimitive(); + + // + + EndScene(); +} + +void GSDevice11::DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c) +{ + 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); + } +} + +void GSDevice11::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset) +{ + 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); +} + +void GSDevice11::IASetVertexBuffer(const void* vertices, size_t stride, size_t count) +{ + ASSERT(m_vertices.count == 0); + + if(count * stride > m_vertices.limit * m_vertices.stride) + { + m_vertices.vb_old = m_vertices.vb; + m_vertices.vb = NULL; + m_vertices.start = 0; + m_vertices.count = 0; + m_vertices.limit = max(count * 3 / 2, 10000); + } + + if(m_vertices.vb == NULL) + { + 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_vertices.vb); + + if(FAILED(hr)) return; + } + + 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; + } + + D3D11_MAPPED_SUBRESOURCE m; + + if(SUCCEEDED(m_ctx->Map(m_vertices.vb, 0, type, 0, &m))) + { + GSVector4i::storent((uint8*)m.pData + m_vertices.start * stride, vertices, count * stride); + + m_ctx->Unmap(m_vertices.vb, 0); + } + + m_vertices.count = count; + m_vertices.stride = stride; + + IASetVertexBuffer(m_vertices.vb, stride); +} + +void GSDevice11::IASetVertexBuffer(ID3D11Buffer* vb, size_t stride) +{ + if(m_vb != vb || m_vb_stride != stride) + { + uint32 offset = 0; + + m_ctx->IASetVertexBuffers(0, 1, &vb, &stride, &offset); + + m_vb = vb; + m_vb_stride = stride; + } +} + +void GSDevice11::IASetInputLayout(ID3D11InputLayout* layout) +{ + if(m_layout != layout) + { + m_ctx->IASetInputLayout(layout); + + m_layout = layout; + } +} + +void GSDevice11::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology) +{ + if(m_topology != topology) + { + m_ctx->IASetPrimitiveTopology(topology); + + m_topology = topology; + } +} + +void GSDevice11::VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb) +{ + if(m_vs != vs) + { + m_ctx->VSSetShader(vs, NULL, 0); + + m_vs = vs; + } + + if(m_vs_cb != vs_cb) + { + m_ctx->VSSetConstantBuffers(0, 1, &vs_cb); + + m_vs_cb = vs_cb; + } +} + +void GSDevice11::GSSetShader(ID3D11GeometryShader* gs) +{ + if(m_gs != gs) + { + m_ctx->GSSetShader(gs, NULL, 0); + + m_gs = gs; + } +} + +void GSDevice11::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1) +{ + ID3D11ShaderResourceView* srv0 = NULL; + ID3D11ShaderResourceView* srv1 = NULL; + + if(sr0) srv0 = *(GSTexture11*)sr0; + if(sr1) srv1 = *(GSTexture11*)sr1; + + if(m_ps_srv[0] != srv0 || m_ps_srv[1] != srv1) + { + ID3D11ShaderResourceView* srvs[] = {srv0, srv1}; + + m_ctx->PSSetShaderResources(0, 2, srvs); + + m_ps_srv[0] = srv0; + m_ps_srv[1] = srv1; + } +} + +void GSDevice11::PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb) +{ + if(m_ps != ps) + { + m_ctx->PSSetShader(ps, NULL, 0); + + m_ps = ps; + } + + if(m_ps_cb != ps_cb) + { + m_ctx->PSSetConstantBuffers(0, 1, &ps_cb); + + m_ps_cb = ps_cb; + } +} + +void GSDevice11::PSSetSamplerState(ID3D11SamplerState* ss0, ID3D11SamplerState* ss1) +{ + if(m_ps_ss[0] != ss0 || m_ps_ss[1] != ss1) + { + ID3D11SamplerState* sss[] = {ss0, ss1}; + + m_ctx->PSSetSamplers(0, 2, sss); + + m_ps_ss[0] = ss0; + m_ps_ss[1] = ss1; + } +} + +void GSDevice11::RSSet(int width, int height, const GSVector4i* scissor) +{ + if(m_viewport.x != width || m_viewport.y != height) + { + D3D11_VIEWPORT vp; + + memset(&vp, 0, sizeof(vp)); + + vp.TopLeftX = 0; + vp.TopLeftY = 0; + vp.Width = width; + vp.Height = height; + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + + m_ctx->RSSetViewports(1, &vp); + + m_viewport = GSVector2i(width, height); + } + + GSVector4i r = scissor ? *scissor : GSVector4i(0, 0, width, height); + + if(!m_scissor.eq(r)) + { + m_ctx->RSSetScissorRects(1, r); + + m_scissor = r; + } +} + +void GSDevice11::OMSetDepthStencilState(ID3D11DepthStencilState* dss, uint8 sref) +{ + if(m_dss != dss || m_sref != sref) + { + m_ctx->OMSetDepthStencilState(dss, sref); + + m_dss = dss; + m_sref = sref; + } +} + +void GSDevice11::OMSetBlendState(ID3D11BlendState* bs, float bf) +{ + if(m_bs != bs || m_bf != bf) + { + float BlendFactor[] = {bf, bf, bf, 0}; + + m_ctx->OMSetBlendState(bs, BlendFactor, 0xffffffff); + + m_bs = bs; + m_bf = bf; + } +} + +void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds) +{ + ID3D11RenderTargetView* rtv = NULL; + ID3D11DepthStencilView* dsv = NULL; + + if(rt) rtv = *(GSTexture11*)rt; + if(ds) dsv = *(GSTexture11*)ds; + + if(m_rtv != rtv || m_dsv != dsv) + { + m_ctx->OMSetRenderTargets(1, &rtv, dsv); + + m_rtv = rtv; + m_dsv = dsv; + } +} + +HRESULT GSDevice11::CompileShader(uint32 id, const string& entry, D3D11_SHADER_MACRO* macro, ID3D11VertexShader** vs, D3D11_INPUT_ELEMENT_DESC* layout, int count, ID3D11InputLayout** il) +{ + HRESULT hr; + + vector m; + + PrepareShaderMacro(m, macro, m_shader.model.c_str()); + + CComPtr shader, error; + + hr = D3DX11CompileFromResource(theApp.GetModuleHandle(), MAKEINTRESOURCE(id), NULL, &m[0], NULL, entry.c_str(), m_shader.vs.c_str(), 0, 0, NULL, &shader, &error, NULL); + + if(error) + { + printf("%s\n", (const char*)error->GetBufferPointer()); + } + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateVertexShader((void*)shader->GetBufferPointer(), shader->GetBufferSize(), NULL, vs); + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateInputLayout(layout, count, shader->GetBufferPointer(), shader->GetBufferSize(), il); + + if(FAILED(hr)) + { + return hr; + } + + return hr; +} + +HRESULT GSDevice11::CompileShader(uint32 id, const string& entry, D3D11_SHADER_MACRO* macro, ID3D11GeometryShader** gs) +{ + HRESULT hr; + + vector m; + + PrepareShaderMacro(m, macro, m_shader.model.c_str()); + + CComPtr shader, error; + + hr = D3DX11CompileFromResource(theApp.GetModuleHandle(), MAKEINTRESOURCE(id), NULL, &m[0], NULL, entry.c_str(), m_shader.gs.c_str(), 0, 0, NULL, &shader, &error, NULL); + + if(error) + { + printf("%s\n", (const char*)error->GetBufferPointer()); + } + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreateGeometryShader((void*)shader->GetBufferPointer(), shader->GetBufferSize(), NULL, gs); + + if(FAILED(hr)) + { + return hr; + } + + return hr; +} + +HRESULT GSDevice11::CompileShader(uint32 id, const string& entry, D3D11_SHADER_MACRO* macro, ID3D11PixelShader** ps) +{ + HRESULT hr; + + vector m; + + PrepareShaderMacro(m, macro, m_shader.model.c_str()); + + CComPtr shader, error; + + hr = D3DX11CompileFromResource(theApp.GetModuleHandle(), MAKEINTRESOURCE(id), NULL, &m[0], NULL, entry.c_str(), m_shader.ps.c_str(), 0, 0, NULL, &shader, &error, NULL); + + if(error) + { + printf("%s\n", (const char*)error->GetBufferPointer()); + } + + if(FAILED(hr)) + { + return hr; + } + + hr = m_dev->CreatePixelShader((void*)shader->GetBufferPointer(), shader->GetBufferSize(),NULL, ps); + + if(FAILED(hr)) + { + return hr; + } + + return hr; +} diff --git a/plugins/GSdx/GSDevice11.h b/plugins/GSdx/GSDevice11.h new file mode 100644 index 0000000000..2fa406e941 --- /dev/null +++ b/plugins/GSdx/GSDevice11.h @@ -0,0 +1,147 @@ +/* + * 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 "GSDevice.h" +#include "GSTexture11.h" + +class GSDevice11 : public GSDevice +{ + ID3D11Buffer* m_vb; + size_t m_vb_stride; + ID3D11InputLayout* m_layout; + D3D11_PRIMITIVE_TOPOLOGY m_topology; + ID3D11VertexShader* m_vs; + ID3D11Buffer* m_vs_cb; + ID3D11GeometryShader* m_gs; + ID3D11ShaderResourceView* m_ps_srv[2]; + ID3D11PixelShader* m_ps; + ID3D11Buffer* m_ps_cb; + ID3D11SamplerState* m_ps_ss[2]; + GSVector2i m_viewport; + GSVector4i m_scissor; + ID3D11DepthStencilState* m_dss; + uint8 m_sref; + ID3D11BlendState* m_bs; + float m_bf; + ID3D11RenderTargetView* m_rtv; + ID3D11DepthStencilView* m_dsv; + + // + + GSTexture* Create(int type, int w, int h, int format); + + void DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c); + void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0); + + // + + D3D_FEATURE_LEVEL m_level; + CComPtr m_dev; + CComPtr m_ctx; + CComPtr m_swapchain; + struct {string model, vs, gs, ps;} m_shader; + + struct + { + CComPtr vb, vb_old; + size_t stride, start, count, limit; + } m_vertices; + +public: // TODO + CComPtr m_rs; + + struct + { + CComPtr il; + CComPtr vs; + CComPtr ps[7]; + CComPtr ln; + CComPtr pt; + CComPtr dss; + CComPtr bs; + } m_convert; + + struct + { + CComPtr ps[2]; + CComPtr cb; + CComPtr bs; + } m_merge; + + struct + { + CComPtr ps[4]; + CComPtr cb; + } m_interlace; + +public: + GSDevice11(); + virtual ~GSDevice11(); + + bool Create(GSWnd* wnd, bool vsync); + bool Reset(int w, int h, bool fs); + + void Flip(); + + void BeginScene(); + void DrawPrimitive(); + void EndScene(); + + 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, int format = 0); + GSTexture* CreateDepthStencil(int w, int h, 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 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, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, bool linear = true); + void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear = true); + + void IASetVertexBuffer(const void* vertices, size_t stride, size_t count); + void IASetVertexBuffer(ID3D11Buffer* vb, size_t stride); + void IASetInputLayout(ID3D11InputLayout* layout); + void IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology); + void VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb); + void GSSetShader(ID3D11GeometryShader* gs); + void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1); + void PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb); + void PSSetSamplerState(ID3D11SamplerState* ss0, ID3D11SamplerState* ss1); + void RSSet(int width, int height, const GSVector4i* scissor = NULL); + void OMSetDepthStencilState(ID3D11DepthStencilState* dss, uint8 sref); + void OMSetBlendState(ID3D11BlendState* bs, float bf); + void OMSetRenderTargets(GSTexture* rt, GSTexture* ds); + + ID3D11Device* operator->() {return m_dev;} + operator ID3D11Device*() {return m_dev;} + operator ID3D11DeviceContext*() {return m_ctx;} + + HRESULT CompileShader(uint32 id, const string& entry, D3D11_SHADER_MACRO* macro, ID3D11VertexShader** vs, D3D11_INPUT_ELEMENT_DESC* layout, int count, ID3D11InputLayout** il); + HRESULT CompileShader(uint32 id, const string& entry, D3D11_SHADER_MACRO* macro, ID3D11GeometryShader** gs); + HRESULT CompileShader(uint32 id, const string& entry, D3D11_SHADER_MACRO* macro, ID3D11PixelShader** ps); +}; diff --git a/plugins/GSdx/GSRendererHW11.cpp b/plugins/GSdx/GSRendererHW11.cpp new file mode 100644 index 0000000000..ec7f11447b --- /dev/null +++ b/plugins/GSdx/GSRendererHW11.cpp @@ -0,0 +1,593 @@ +/* + * 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 "GSRendererHW11.h" +#include "GSCrc.h" +#include "resource.h" + +GSRendererHW11::GSRendererHW11(uint8* base, bool mt, void (*irq)()) + : GSRendererHW(base, mt, irq, new GSDevice11(), new GSTextureCache11(this)) +{ + InitVertexKick(); +} + +bool GSRendererHW11::Create(const string& title) +{ + if(!__super::Create(title)) + return false; + + if(!m_tfx.Create((GSDevice11*)m_dev)) + return false; + + // + + D3D11_DEPTH_STENCIL_DESC dsd; + + memset(&dsd, 0, sizeof(dsd)); + + dsd.DepthEnable = false; + dsd.StencilEnable = true; + dsd.StencilReadMask = 1; + dsd.StencilWriteMask = 1; + dsd.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsd.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsd.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsd.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsd.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + dsd.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; + dsd.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsd.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + + (*(GSDevice11*)m_dev)->CreateDepthStencilState(&dsd, &m_date.dss); + + D3D11_BLEND_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + (*(GSDevice11*)m_dev)->CreateBlendState(&bd, &m_date.bs); + + // + + return true; +} + +template +void GSRendererHW11::VertexKick(bool skip) +{ + GSVertexHW11& dst = m_vl.AddTail(); + + dst.vi[0] = m_v.vi[0]; + dst.vi[1] = m_v.vi[1]; + + if(tme && fst) + { + GSVector4::storel(&dst.ST, m_v.GetUV()); + } + + int count = 0; + + if(GSVertexHW11* v = DrawingKick(skip, count)) + { + GSVector4i scissor = m_context->scissor.dx10; + + #if _M_SSE >= 0x401 + + GSVector4i pmin, pmax, v0, v1, v2; + + switch(prim) + { + case GS_POINTLIST: + v0 = GSVector4i::load((int)v[0].p.xy).upl16(); + pmin = v0; + pmax = v0; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + v0 = GSVector4i::load((int)v[0].p.xy); + v1 = GSVector4i::load((int)v[1].p.xy); + pmin = v0.min_u16(v1).upl16(); + pmax = v0.max_u16(v1).upl16(); + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + v0 = GSVector4i::load((int)v[0].p.xy); + v1 = GSVector4i::load((int)v[1].p.xy); + v2 = GSVector4i::load((int)v[2].p.xy); + pmin = v0.min_u16(v1).min_u16(v2).upl16(); + pmax = v0.max_u16(v1).max_u16(v2).upl16(); + break; + } + + GSVector4i test = (pmax < scissor) | (pmin > scissor.zwxy()); + + if(test.mask() & 0xff) + { + return; + } + + #else + + switch(prim) + { + case GS_POINTLIST: + if(v[0].p.x < scissor.x + || v[0].p.x > scissor.z + || v[0].p.y < scissor.y + || v[0].p.y > scissor.w) + { + return; + } + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + if(v[0].p.x < scissor.x && v[1].p.x < scissor.x + || v[0].p.x > scissor.z && v[1].p.x > scissor.z + || v[0].p.y < scissor.y && v[1].p.y < scissor.y + || v[0].p.y > scissor.w && v[1].p.y > scissor.w) + { + return; + } + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + if(v[0].p.x < scissor.x && v[1].p.x < scissor.x && v[2].p.x < scissor.x + || v[0].p.x > scissor.z && v[1].p.x > scissor.z && v[2].p.x > scissor.z + || v[0].p.y < scissor.y && v[1].p.y < scissor.y && v[2].p.y < scissor.y + || v[0].p.y > scissor.w && v[1].p.y > scissor.w && v[2].p.y > scissor.w) + { + return; + } + break; + } + + #endif + + m_count += count; + } +} + +void GSRendererHW11::Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex) +{ + GSDrawingEnvironment& env = m_env; + GSDrawingContext* context = m_context; +/* + if(s_dump) + { + TRACE(_T("\n")); + + TRACE(_T("PRIM = %d, ZMSK = %d, ZTE = %d, ZTST = %d, ATE = %d, ATST = %d, AFAIL = %d, AREF = %02x\n"), + PRIM->PRIM, context->ZBUF.ZMSK, + context->TEST.ZTE, context->TEST.ZTST, + context->TEST.ATE, context->TEST.ATST, context->TEST.AFAIL, context->TEST.AREF); + + for(int i = 0; i < m_count; i++) + { + TRACE(_T("[%d] %3.0f %3.0f %3.0f %3.0f\n"), i, (float)m_vertices[i].p.x / 16, (float)m_vertices[i].p.y / 16, (float)m_vertices[i].p.z, (float)m_vertices[i].a); + } + } +*/ + D3D11_PRIMITIVE_TOPOLOGY topology; + int prims = 0; + + switch(prim) + { + case GS_POINTLIST: + topology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + prims = m_count; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + topology = D3D11_PRIMITIVE_TOPOLOGY_LINELIST; + prims = m_count / 2; + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + case GS_TRIANGLEFAN: + topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + prims = m_count / 3; + break; + default: + __assume(0); + } + + m_perfmon.Put(GSPerfMon::Prim, prims); + m_perfmon.Put(GSPerfMon::Draw, 1); + + // date + + SetupDATE(rt, ds); + + // + + m_dev->BeginScene(); + + // om + + GSTextureFX11::OMDepthStencilSelector om_dssel; + + om_dssel.zte = context->TEST.ZTE; + om_dssel.ztst = context->TEST.ZTST; + om_dssel.zwe = !context->ZBUF.ZMSK; + om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0; + + GSTextureFX11::OMBlendSelector om_bsel; + + om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1; + om_bsel.a = context->ALPHA.A; + om_bsel.b = context->ALPHA.B; + om_bsel.c = context->ALPHA.C; + om_bsel.d = context->ALPHA.D; + om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff; + om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00; + om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000; + om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000; + + float bf = (float)(int)context->ALPHA.FIX / 0x80; + + // vs + + GSTextureFX11::VSSelector vs_sel; + + vs_sel.bppz = 0; + vs_sel.tme = PRIM->TME; + vs_sel.fst = PRIM->FST; + vs_sel.prim = prim; + + if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe) + { + if(context->ZBUF.PSM == PSM_PSMZ24) + { + if(WrapZ(0xffffff)) + { + vs_sel.bppz = 1; + om_dssel.ztst = 1; + } + } + else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S) + { + if(WrapZ(0xffff)) + { + vs_sel.bppz = 2; + om_dssel.ztst = 1; + } + } + } + + GSTextureFX11::VSConstantBuffer vs_cb; + + float sx = 2.0f * rt->m_scale.x / (rt->GetWidth() * 16); + float sy = 2.0f * rt->m_scale.y / (rt->GetHeight() * 16); + float ox = (float)(int)context->XYOFFSET.OFX; + float oy = (float)(int)context->XYOFFSET.OFY; + float ox2 = 1.0f / rt->GetWidth(); + float oy2 = 1.0f / rt->GetHeight(); + + vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f); + vs_cb.VertexOffset = GSVector4(ox * sx - ox2 + 1, -(oy * sy - oy2 + 1), 0.0f, -1.0f); + vs_cb.TextureScale = GSVector2(1.0f, 1.0f); + + if(PRIM->TME && PRIM->FST) + { + vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW); + vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH); + } + + // gs + + GSTextureFX11::GSSelector gs_sel; + + gs_sel.iip = PRIM->IIP; + gs_sel.prim = GSUtil::GetPrimClass(prim); + + // ps + + GSTextureFX11::PSSelector ps_sel; + + ps_sel.fst = PRIM->FST; + ps_sel.wms = context->CLAMP.WMS; + ps_sel.wmt = context->CLAMP.WMT; + ps_sel.bpp = 0; + ps_sel.aem = env.TEXA.AEM; + ps_sel.tfx = context->TEX0.TFX; + ps_sel.tcc = context->TEX0.TCC; + ps_sel.ate = context->TEST.ATE; + ps_sel.atst = context->TEST.ATST; + ps_sel.fog = PRIM->FGE; + ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1; + ps_sel.fba = context->FBA.FBA; + ps_sel.aout = context->FRAME.PSM == PSM_PSMCT16 || context->FRAME.PSM == PSM_PSMCT16S || (context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0; + ps_sel.ltf = m_filter == 2 ? context->TEX1.IsLinear() : m_filter; + + GSTextureFX11::PSSamplerSelector ps_ssel; + + ps_ssel.tau = 0; + ps_ssel.tav = 0; + ps_ssel.ltf = ps_sel.ltf; + + GSTextureFX11::PSConstantBuffer ps_cb; + + ps_cb.FogColor_AREF = GSVector4((int)env.FOGCOL.FCR, (int)env.FOGCOL.FCG, (int)env.FOGCOL.FCB, (int)context->TEST.AREF) / 255; + + if(context->TEST.ATST == 2 || context->TEST.ATST == 5) + { + ps_cb.FogColor_AREF.a -= 0.9f / 255; + } + else if(context->TEST.ATST == 3 || context->TEST.ATST == 6) + { + ps_cb.FogColor_AREF.a += 0.9f / 255; + } + + if(tex) + { + ps_sel.bpp = tex->m_bpp; + + int w = tex->m_texture->GetWidth(); + int h = tex->m_texture->GetHeight(); + + ps_cb.WH_TA = GSVector4((int)(1 << context->TEX0.TW), (int)(1 << context->TEX0.TH), env.TEXA.TA0, env.TEXA.TA1) / GSVector4(1, 255).xxyy(); + ps_cb.HalfTexel = GSVector4(-0.5f, 0.5f).xxyy() / GSVector4(w, h).xyxy(); + + switch(context->CLAMP.WMS) + { + case 0: + ps_ssel.tau = 1; + break; + case 1: + ps_ssel.tau = 0; + break; + case 2: + ps_cb.MinMax.x = ((float)(int)context->CLAMP.MINU) / (1 << context->TEX0.TW); + ps_cb.MinMax.z = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW); + ps_cb.MinMaxF.x = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW); + ps_cb.MinMaxF.z = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW); + ps_ssel.tau = 0; + break; + case 3: + ps_cb.MskFix.x = context->CLAMP.MINU; + ps_cb.MskFix.z = context->CLAMP.MAXU; + ps_ssel.tau = 1; + break; + default: + __assume(0); + } + + switch(context->CLAMP.WMT) + { + case 0: + ps_ssel.tav = 1; + break; + case 1: + ps_ssel.tav = 0; + break; + case 2: + ps_cb.MinMax.y = ((float)(int)context->CLAMP.MINV) / (1 << context->TEX0.TH); + ps_cb.MinMax.w = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH); + ps_cb.MinMaxF.y = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH); + ps_cb.MinMaxF.w = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH); + ps_ssel.tav = 0; + break; + case 3: + ps_cb.MskFix.y = context->CLAMP.MINV; + ps_cb.MskFix.w = context->CLAMP.MAXV; + ps_ssel.tav = 1; + break; + default: + __assume(0); + } + } + else + { + ps_sel.tfx = 4; + } + + // rs + + int w = rt->GetWidth(); + int h = rt->GetHeight(); + + GSVector4i scissor = GSVector4i(GSVector4(rt->m_scale).xyxy() * context->scissor.in).rintersect(GSVector4i(0, 0, w, h)); + + // + + m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds); + m_tfx.SetupIA(m_vertices, m_count, topology); + m_tfx.SetupVS(vs_sel, &vs_cb); + m_tfx.SetupGS(gs_sel); + m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, tex ? tex->m_texture : NULL, tex ? tex->m_palette : NULL); + m_tfx.SetupRS(w, h, scissor); + + // draw + + if(context->TEST.DoFirstPass()) + { + m_tfx.Draw(); + } + + if(context->TEST.DoSecondPass()) + { + ASSERT(!env.PABE.PABE); + + static const uint32 iatst[] = {1, 0, 5, 6, 7, 2, 3, 4}; + + ps_sel.atst = iatst[ps_sel.atst]; + + m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel); + + bool z = om_dssel.zwe; + bool r = om_bsel.wr; + bool g = om_bsel.wg; + bool b = om_bsel.wb; + bool a = om_bsel.wa; + + switch(context->TEST.AFAIL) + { + case 0: z = r = g = b = a = false; break; // none + case 1: z = false; break; // rgba + case 2: r = g = b = a = false; break; // z + case 3: z = a = false; break; // rgb + default: __assume(0); + } + + if(z || r || g || b || a) + { + om_dssel.zwe = z; + om_bsel.wr = r; + om_bsel.wg = g; + om_bsel.wb = b; + om_bsel.wa = a; + + m_tfx.UpdateOM(om_dssel, om_bsel, bf); + + m_tfx.Draw(); + } + } + + m_dev->EndScene(); +} + +bool GSRendererHW11::WrapZ(uint32 maxz) +{ + // should only run once if z values are in the z buffer range + + for(int i = 0, j = m_count; i < j; i++) + { + if(m_vertices[i].p.z <= maxz) + { + return false; + } + } + + return true; +} + +void GSRendererHW11::SetupDATE(GSTexture* rt, GSTexture* ds) +{ + if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000) + + GSDevice11* dev = (GSDevice11*)m_dev; + + int w = rt->GetWidth(); + int h = rt->GetHeight(); + + if(GSTexture* t = dev->CreateRenderTarget(w, h)) + { + // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows + + GSVector4 mm; + + // TODO + + mm = GSVector4(-1, -1, 1, 1); + + // if(m_count < 100) + { + GSVector4 pmin(65535, 65535, 0, 0); + GSVector4 pmax = GSVector4::zero(); + + for(int i = 0, j = m_count; i < j; i++) + { + GSVector4 p(m_vertices[i].vi[0].uph16()); + + pmin = p.minv(pmin); + pmax = p.maxv(pmax); + } + + mm += pmin.xyxy(pmax); + + float sx = 2.0f * rt->m_scale.x / (w * 16); + float sy = 2.0f * rt->m_scale.y / (h * 16); + float ox = (float)(int)m_context->XYOFFSET.OFX; + float oy = (float)(int)m_context->XYOFFSET.OFY; + + mm.x = (mm.x - ox) * sx - 1; + mm.y = (mm.y - oy) * sy - 1; + mm.z = (mm.z - ox) * sx - 1; + mm.w = (mm.w - oy) * sy - 1; + + if(mm.x < -1) mm.x = -1; + if(mm.y < -1) mm.y = -1; + if(mm.z > +1) mm.z = +1; + if(mm.w > +1) mm.w = +1; + } + + GSVector4 uv = (mm + 1.0f) / 2.0f; + + // + + dev->BeginScene(); + + dev->ClearStencil(ds, 0); + + // om + + dev->OMSetDepthStencilState(m_date.dss, 1); + dev->OMSetBlendState(m_date.bs, 0); + dev->OMSetRenderTargets(t, ds); + + // ia + + GSVertexPT1 vertices[] = + { + {GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)}, + {GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)}, + {GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)}, + {GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)}, + }; + + dev->IASetVertexBuffer(vertices, sizeof(vertices[0]), countof(vertices)); + dev->IASetInputLayout(dev->m_convert.il); + dev->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // vs + + dev->VSSetShader(dev->m_convert.vs, NULL); + + // gs + + dev->GSSetShader(NULL); + + // ps + + dev->PSSetShaderResources(rt, NULL); + dev->PSSetShader(dev->m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL); + dev->PSSetSamplerState(dev->m_convert.pt, NULL); + + // rs + + dev->RSSet(w, h); + + // set + + dev->DrawPrimitive(); + + // + + dev->EndScene(); + + dev->Recycle(t); + } +} diff --git a/plugins/GSdx/GSRendererHW11.h b/plugins/GSdx/GSRendererHW11.h new file mode 100644 index 0000000000..f3763a7dd1 --- /dev/null +++ b/plugins/GSdx/GSRendererHW11.h @@ -0,0 +1,52 @@ +/* + * 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 "GSRendererHW.h" +#include "GSVertexHW.h" +#include "GSTextureCache11.h" +#include "GSTextureFX11.h" + +class GSRendererHW11 : public GSRendererHW +{ + bool WrapZ(uint32 maxz); + +protected: + GSTextureFX11 m_tfx; + + void Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex); + + struct + { + CComPtr dss; + CComPtr bs; + } m_date; + + void SetupDATE(GSTexture* rt, GSTexture* ds); + +public: + GSRendererHW11(uint8* base, bool mt, void (*irq)()); + + bool Create(const string& title); + + template void VertexKick(bool skip); +}; \ No newline at end of file diff --git a/plugins/GSdx/GSTexture11.cpp b/plugins/GSdx/GSTexture11.cpp new file mode 100644 index 0000000000..c80cc7aae6 --- /dev/null +++ b/plugins/GSdx/GSTexture11.cpp @@ -0,0 +1,200 @@ +/* + * 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 "GSTexture11.h" + +GSTexture11::GSTexture11(ID3D11Texture2D* texture) + : m_texture(texture) +{ + ASSERT(m_texture); + + m_texture->GetDevice(&m_dev); + m_texture->GetDesc(&m_desc); + + m_dev->GetImmediateContext(&m_ctx); +} + +int GSTexture11::GetType() const +{ + if(m_desc.BindFlags & D3D11_BIND_RENDER_TARGET) return GSTexture::RenderTarget; + if(m_desc.BindFlags & D3D11_BIND_DEPTH_STENCIL) return GSTexture::DepthStencil; + if(m_desc.BindFlags & D3D11_BIND_SHADER_RESOURCE) return GSTexture::Texture; + if(m_desc.Usage == D3D11_USAGE_STAGING) return GSTexture::Offscreen; + return GSTexture::None; +} + +int GSTexture11::GetWidth() const +{ + return m_desc.Width; +} + +int GSTexture11::GetHeight() const +{ + return m_desc.Height; +} + +int GSTexture11::GetFormat() const +{ + return m_desc.Format; +} + +bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch) +{ + 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; +} + +bool GSTexture11::Map(GSMap& m, const GSVector4i* r) +{ + if(r != NULL) + { + // ASSERT(0); // not implemented + + return false; + } + + if(m_texture) + { + 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; +} + +void GSTexture11::Unmap() +{ + if(m_texture) + { + m_ctx->Unmap(m_texture, 0); + } +} + +bool GSTexture11::Save(const string& fn, bool dds) +{ + 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)(((float*)s)[x*2] * UINT_MAX); + } + } + + 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())); +} + +GSTexture11::operator ID3D11Texture2D*() +{ + return m_texture; +} + +GSTexture11::operator ID3D11ShaderResourceView*() +{ + if(!m_srv && m_dev && m_texture) + { + m_dev->CreateShaderResourceView(m_texture, NULL, &m_srv); + } + + return m_srv; +} + +GSTexture11::operator ID3D11RenderTargetView*() +{ + ASSERT(m_dev); + + if(!m_rtv && m_dev && m_texture) + { + m_dev->CreateRenderTargetView(m_texture, NULL, &m_rtv); + } + + return m_rtv; +} + +GSTexture11::operator ID3D11DepthStencilView*() +{ + if(!m_dsv && m_dev && m_texture) + { + m_dev->CreateDepthStencilView(m_texture, NULL, &m_dsv); + } + + return m_dsv; +} diff --git a/plugins/GSdx/GSTexture11.h b/plugins/GSdx/GSTexture11.h new file mode 100644 index 0000000000..6b3b16fb6c --- /dev/null +++ b/plugins/GSdx/GSTexture11.h @@ -0,0 +1,53 @@ +/* + * 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 "GSTexture.h" + +class GSTexture11 : public GSTexture +{ + CComPtr m_dev; + CComPtr m_ctx; + CComPtr m_texture; + D3D11_TEXTURE2D_DESC m_desc; + CComPtr m_srv; + CComPtr m_rtv; + CComPtr m_dsv; + +public: + explicit GSTexture11(ID3D11Texture2D* texture); + + int GetType() const; + int GetWidth() const; + int GetHeight() const; + int GetFormat() const; + + bool Update(const GSVector4i& r, const void* data, int pitch); + bool Map(GSMap& m, const GSVector4i* r); + void Unmap(); + bool Save(const string& fn, bool dds = false); + + operator ID3D11Texture2D*(); + operator ID3D11ShaderResourceView*(); + operator ID3D11RenderTargetView*(); + operator ID3D11DepthStencilView*(); +}; diff --git a/plugins/GSdx/GSTextureCache11.cpp b/plugins/GSdx/GSTextureCache11.cpp new file mode 100644 index 0000000000..221bfb7cd3 --- /dev/null +++ b/plugins/GSdx/GSTextureCache11.cpp @@ -0,0 +1,309 @@ +/* + * 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 "GSTextureCache11.h" + +// GSTextureCache11 + +GSTextureCache11::GSTextureCache11(GSRenderer* r) + : GSTextureCache(r) +{ +} + +// GSRenderTargetHW10 + +void GSTextureCache11::GSRenderTargetHW11::Read(const GSVector4i& r) +{ + if(m_TEX0.PSM != PSM_PSMCT32 + && m_TEX0.PSM != PSM_PSMCT24 + && m_TEX0.PSM != PSM_PSMCT16 + && m_TEX0.PSM != PSM_PSMCT16S) + { + //ASSERT(0); + return; + } + + if(!m_dirty.empty()) + { + return; + } + + // printf("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n", r.left, r.top, r.right, r.bottom, m_TEX0.TBP0); + + // m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1); + + int w = r.width(); + int h = r.height(); + + GSVector4 src = GSVector4(r) * GSVector4(m_texture->m_scale).xyxy() / GSVector4(m_texture->GetSize()).xyxy(); + + DXGI_FORMAT format = m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; + + if(GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(m_texture, src, w, h, format)) + { + GSTexture::GSMap m; + + if(offscreen->Map(m)) + { + // TODO: block level write + + uint32 bp = m_TEX0.TBP0; + uint32 bw = m_TEX0.TBW; + + GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa; + + if(m_TEX0.PSM == PSM_PSMCT32) + { + for(int y = r.top; y < r.bottom; y++, m.bits += m.pitch) + { + uint32 addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel32(addr + offset[x], ((uint32*)m.bits)[i]); + } + } + } + else if(m_TEX0.PSM == PSM_PSMCT24) + { + for(int y = r.top; y < r.bottom; y++, m.bits += m.pitch) + { + uint32 addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel24(addr + offset[x], ((uint32*)m.bits)[i]); + } + } + } + else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S) + { + for(int y = r.top; y < r.bottom; y++, m.bits += m.pitch) + { + uint32 addr = pa(0, y, bp, bw); + int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7]; + + for(int x = r.left, i = 0; x < r.right; x++, i++) + { + m_renderer->m_mem.WritePixel16(addr + offset[x], ((uint16*)m.bits)[i]); + } + } + } + else + { + ASSERT(0); + } + + offscreen->Unmap(); + } + + m_renderer->m_dev->Recycle(offscreen); + } +} + +// GSTextureHW10 + +bool GSTextureCache11::GSCachedTextureHW11::Create() +{ + // m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1); + + m_TEX0 = m_renderer->m_context->TEX0; + m_TEXA = m_renderer->m_env.TEXA; + + m_bpp = 0; + + ASSERT(m_texture == NULL); + + m_texture = m_renderer->m_dev->CreateTexture(1 << m_TEX0.TW, 1 << m_TEX0.TH); + + return m_texture != NULL; +} + +bool GSTextureCache11::GSCachedTextureHW11::Create(GSRenderTarget* rt) +{ + // TODO: clean up this mess + + rt->Update(); + + // m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1); + + m_TEX0 = m_renderer->m_context->TEX0; + m_TEXA = m_renderer->m_env.TEXA; + + m_rendered = true; + + int tw = 1 << m_TEX0.TW; + int th = 1 << m_TEX0.TH; + int tp = (int)m_TEX0.TW << 6; + + // do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows) + + int w = (int)(rt->m_texture->m_scale.x * tw); + int h = (int)(rt->m_texture->m_scale.y * th); + + GSVector2i rtsize = rt->m_texture->GetSize(); + + // pitch conversion + + if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM + { + // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left) + + // ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO) + + ASSERT(m_texture == NULL); + + m_texture = m_renderer->m_dev->CreateRenderTarget(rtsize.x, rtsize.y); + + GSVector4 size = GSVector4(rtsize).xyxy(); + GSVector4 scale = GSVector4(rt->m_texture->m_scale).xyxy(); + + int bw = 64; + int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64; + + GSVector4i br(0, 0, bw, bh); + + int sw = (int)rt->m_TEX0.TBW << 6; + + int dw = (int)m_TEX0.TBW << 6; + int dh = 1 << m_TEX0.TH; + + if(sw != 0) + for(int dy = 0; dy < dh; dy += bh) + { + for(int dx = 0; dx < dw; dx += bw) + { + int o = dy * dw / bh + dx; + + int sx = o % sw; + int sy = o / sw; + + GSVector4 src = GSVector4(GSVector4i(sx, sy).xyxy() + br) * scale / size; + GSVector4 dst = GSVector4(GSVector4i(dx, dy).xyxy() + br) * scale; + + m_renderer->m_dev->StretchRect(rt->m_texture, src, m_texture, dst); + + // TODO: this is quite a lot of StretchRect, do it with one Draw + } + } + } + else if(tw < tp) + { + // FIXME: timesplitters blurs the render target by blending itself over a couple of times + + if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00)) + { + return false; + } + } + + // width/height conversion + + GSVector2 scale = rt->m_texture->m_scale; + + GSVector4 dst(0, 0, w, h); + + if(w > rtsize.x) + { + scale.x = (float)rtsize.x / tw; + dst.z = (float)rtsize.x * scale.x / rt->m_texture->m_scale.x; + w = rtsize.x; + } + + if(h > rtsize.y) + { + scale.y = (float)rtsize.y / th; + dst.w = (float)rtsize.y * scale.y / rt->m_texture->m_scale.y; + h = rtsize.y; + } + + GSVector4 src(0, 0, w, h); + + GSTexture* st = m_texture ? m_texture : rt->m_texture; + GSTexture* dt = m_renderer->m_dev->CreateRenderTarget(w, h); + + if(!m_texture) + { + m_texture = dt; + } + + if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w) + { + D3D11_BOX box = {0, 0, 0, w, h, 1}; + + ID3D11DeviceContext* ctx = *(GSDevice11*)m_renderer->m_dev; + + ctx->CopySubresourceRegion(*(GSTexture11*)dt, 0, 0, 0, 0, *(GSTexture11*)st, 0, &box); + } + else + { + src.z /= st->GetWidth(); + src.w /= st->GetHeight(); + + m_renderer->m_dev->StretchRect(st, src, dt, dst); + } + + if(dt != m_texture) + { + m_renderer->m_dev->Recycle(m_texture); + + m_texture = dt; + } + + m_texture->m_scale = scale; + + switch(m_TEX0.PSM) + { + case PSM_PSMCT32: + m_bpp = 0; + break; + case PSM_PSMCT24: + m_bpp = 1; + break; + case PSM_PSMCT16: + case PSM_PSMCT16S: + m_bpp = 2; + break; + case PSM_PSMT8H: + m_bpp = 3; + m_palette = m_renderer->m_dev->CreateTexture(256, 1); + m_initpalette = true; + break; + case PSM_PSMT4HL: + case PSM_PSMT4HH: + ASSERT(0); // TODO + break; + } + + return true; +} + +bool GSTextureCache11::GSCachedTextureHW11::Create(GSDepthStencil* ds) +{ + m_rendered = true; + + // TODO + + return false; +} diff --git a/plugins/GSdx/GSTextureCache11.h b/plugins/GSdx/GSTextureCache11.h new file mode 100644 index 0000000000..ec3d883f81 --- /dev/null +++ b/plugins/GSdx/GSTextureCache11.h @@ -0,0 +1,60 @@ +/* + * 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 "GSDevice11.h" + +class GSTextureCache11 : public GSTextureCache +{ + class GSRenderTargetHW11 : public GSRenderTarget + { + public: + explicit GSRenderTargetHW11(GSRenderer* r) : GSRenderTarget(r) {} + + void Read(const GSVector4i& r); + }; + + class GSDepthStencilHW11 : public GSDepthStencil + { + public: + explicit GSDepthStencilHW11(GSRenderer* r) : GSDepthStencil(r) {} + }; + + class GSCachedTextureHW11 : public GSCachedTexture + { + public: + explicit GSCachedTextureHW11(GSRenderer* r) : GSCachedTexture(r) {} + + bool Create(); + bool Create(GSRenderTarget* rt); + bool Create(GSDepthStencil* ds); + }; + +protected: + GSRenderTarget* CreateRenderTarget() {return new GSRenderTargetHW11(m_renderer);} + GSDepthStencil* CreateDepthStencil() {return new GSDepthStencilHW11(m_renderer);} + GSCachedTexture* CreateTexture() {return new GSCachedTextureHW11(m_renderer);} + +public: + GSTextureCache11(GSRenderer* r); +}; diff --git a/plugins/GSdx/GSTextureFX11.cpp b/plugins/GSdx/GSTextureFX11.cpp new file mode 100644 index 0000000000..d0efbc7ee3 --- /dev/null +++ b/plugins/GSdx/GSTextureFX11.cpp @@ -0,0 +1,526 @@ +/* + * 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 "GSTextureFX11.h" +#include "resource.h" + +GSTextureFX11::GSTextureFX11() + : m_dev(NULL) +{ + memset(&m_vs_cb_cache, 0, sizeof(m_vs_cb_cache)); + memset(&m_ps_cb_cache, 0, sizeof(m_ps_cb_cache)); +} + +bool GSTextureFX11::Create(GSDevice11* dev) +{ + m_dev = dev; + + VSSelector sel; + + sel.bppz = 0; + sel.tme = 0; + sel.fst = 0; + + VSConstantBuffer cb; + + SetupVS(sel, &cb); // creates layout + + HRESULT hr; + + D3D11_BUFFER_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(VSConstantBuffer); + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vs_cb); + + if(FAILED(hr)) return false; + + memset(&bd, 0, sizeof(bd)); + + bd.ByteWidth = sizeof(PSConstantBuffer); + bd.Usage = D3D11_USAGE_DEFAULT; + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_ps_cb); + + if(FAILED(hr)) return false; + + D3D11_SAMPLER_DESC sd; + + memset(&sd, 0, sizeof(sd)); + + sd.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + sd.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + sd.MaxLOD = FLT_MAX; + sd.MaxAnisotropy = 16; + sd.ComparisonFunc = D3D11_COMPARISON_NEVER; + + hr = (*m_dev)->CreateSamplerState(&sd, &m_palette_ss); + + if(FAILED(hr)) return false; + + // + + return true; +} + +bool GSTextureFX11::SetupIA(const GSVertexHW11* vertices, int count, D3D11_PRIMITIVE_TOPOLOGY prim) +{ + m_dev->IASetVertexBuffer(vertices, sizeof(vertices[0]), count); + m_dev->IASetInputLayout(m_il); + m_dev->IASetPrimitiveTopology(prim); + + return true; +} + +bool GSTextureFX11::SetupVS(VSSelector sel, const VSConstantBuffer* cb) +{ + hash_map >::const_iterator i = m_vs.find(sel); + + if(i == m_vs.end()) + { + string str[4]; + + str[0] = format("%d", sel.bppz); + str[1] = format("%d", sel.tme); + str[2] = format("%d", sel.fst); + str[3] = format("%d", sel.prim); + + D3D11_SHADER_MACRO macro[] = + { + {"VS_BPPZ", str[0].c_str()}, + {"VS_TME", str[1].c_str()}, + {"VS_FST", str[2].c_str()}, + {"VS_PRIM", str[3].c_str()}, + {NULL, NULL}, + }; + + D3D11_INPUT_ELEMENT_DESC layout[] = + { + {"POSITION", 0, DXGI_FORMAT_R16G16_UINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"POSITION", 1, DXGI_FORMAT_R32_UINT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + CComPtr il; + CComPtr vs; + + m_dev->CompileShader(IDR_TFX_FX, "vs_main", macro, &vs, layout, countof(layout), &il); + + if(m_il == NULL) + { + m_il = il; + } + + m_vs[sel] = vs; + + i = m_vs.find(sel); + } + + if(m_vs_cb_cache.Update(cb)) + { + ID3D11DeviceContext* ctx = *m_dev; + + ctx->UpdateSubresource(m_vs_cb, 0, NULL, cb, 0, 0); + } + + m_dev->VSSetShader((*i).second, m_vs_cb); + + return true; +} + +bool GSTextureFX11::SetupGS(GSSelector sel) +{ + HRESULT hr; + + ID3D11GeometryShader* gs = NULL; + + if(sel.prim > 0 && (sel.iip == 0 || sel.prim == 3)) // geometry shader works in every case, but not needed + { + hash_map >::const_iterator i = m_gs.find(sel); + + if(i != m_gs.end()) + { + gs = (*i).second; + } + else + { + string str[2]; + + str[0] = format("%d", sel.iip); + str[1] = format("%d", sel.prim); + + D3D11_SHADER_MACRO macro[] = + { + {"IIP", str[0].c_str()}, + {"PRIM", str[1].c_str()}, + {NULL, NULL}, + }; + + hr = m_dev->CompileShader(IDR_TFX_FX, "gs_main", macro, &gs); + + m_gs[sel] = gs; + } + } + + m_dev->GSSetShader(gs); + + return true; +} + +bool GSTextureFX11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, GSTexture* tex, GSTexture* pal) +{ + m_dev->PSSetShaderResources(tex, pal); + + UpdatePS(sel, cb, ssel); + + return true; +} + +void GSTextureFX11::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel) +{ + HRESULT hr; + + hash_map >::const_iterator i = m_ps.find(sel); + + if(i == m_ps.end()) + { + string str[14]; + + str[0] = format("%d", sel.fst); + str[1] = format("%d", sel.wms); + str[2] = format("%d", sel.wmt); + str[3] = format("%d", sel.bpp); + str[4] = format("%d", sel.aem); + str[5] = format("%d", sel.tfx); + str[6] = format("%d", sel.tcc); + str[7] = format("%d", sel.ate); + str[8] = format("%d", sel.atst); + str[9] = format("%d", sel.fog); + str[10] = format("%d", sel.clr1); + str[11] = format("%d", sel.fba); + str[12] = format("%d", sel.aout); + str[13] = format("%d", sel.ltf); + + D3D11_SHADER_MACRO macro[] = + { + {"FST", str[0].c_str()}, + {"WMS", str[1].c_str()}, + {"WMT", str[2].c_str()}, + {"BPP", str[3].c_str()}, + {"AEM", str[4].c_str()}, + {"TFX", str[5].c_str()}, + {"TCC", str[6].c_str()}, + {"ATE", str[7].c_str()}, + {"ATST", str[8].c_str()}, + {"FOG", str[9].c_str()}, + {"CLR1", str[10].c_str()}, + {"FBA", str[11].c_str()}, + {"AOUT", str[12].c_str()}, + {"LTF", str[13].c_str()}, + {NULL, NULL}, + }; + + CComPtr ps; + + hr = m_dev->CompileShader(IDR_TFX_FX, "ps_main", macro, &ps); + + m_ps[sel] = ps; + + i = m_ps.find(sel); + } + + if(m_ps_cb_cache.Update(cb)) + { + ID3D11DeviceContext* ctx = *m_dev; + + ctx->UpdateSubresource(m_ps_cb, 0, NULL, cb, 0, 0); + } + + m_dev->PSSetShader((*i).second, m_ps_cb); + + ID3D11SamplerState* ss0 = NULL; + ID3D11SamplerState* ss1 = NULL; + + if(sel.tfx != 4) + { + if(!(sel.bpp < 3 && sel.wms < 3 && sel.wmt < 3)) + { + ssel.ltf = 0; + } + + hash_map >::const_iterator i = m_ps_ss.find(ssel); + + if(i != m_ps_ss.end()) + { + ss0 = (*i).second; + } + else + { + D3D11_SAMPLER_DESC sd; + + memset(&sd, 0, sizeof(sd)); + + sd.Filter = ssel.ltf ? D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_POINT; + + sd.AddressU = ssel.tau ? D3D11_TEXTURE_ADDRESS_WRAP : D3D11_TEXTURE_ADDRESS_CLAMP; + sd.AddressV = ssel.tav ? D3D11_TEXTURE_ADDRESS_WRAP : D3D11_TEXTURE_ADDRESS_CLAMP; + sd.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + + sd.MaxLOD = FLT_MAX; + sd.MaxAnisotropy = 16; + sd.ComparisonFunc = D3D11_COMPARISON_NEVER; + + hr = (*m_dev)->CreateSamplerState(&sd, &ss0); + + m_ps_ss[ssel] = ss0; + } + + if(sel.bpp == 3) + { + ss1 = m_palette_ss; + } + } + + m_dev->PSSetSamplerState(ss0, ss1); +} + +void GSTextureFX11::SetupRS(int w, int h, const GSVector4i& scissor) +{ + m_dev->RSSet(w, h, &scissor); +} + +void GSTextureFX11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, GSTexture* rt, GSTexture* ds) +{ + UpdateOM(dssel, bsel, bf); + + m_dev->OMSetRenderTargets(rt, ds); +} + +void GSTextureFX11::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf) +{ + HRESULT hr; + + hash_map >::const_iterator i = m_om_dss.find(dssel); + + if(i == m_om_dss.end()) + { + D3D11_DEPTH_STENCIL_DESC dsd; + + memset(&dsd, 0, sizeof(dsd)); + + if(dssel.date) + { + dsd.StencilEnable = true; + dsd.StencilReadMask = 1; + dsd.StencilWriteMask = 1; + dsd.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL; + dsd.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + dsd.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsd.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + dsd.BackFace.StencilFunc = D3D11_COMPARISON_EQUAL; + dsd.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + dsd.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + dsd.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; + } + + if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe)) + { + static const D3D11_COMPARISON_FUNC ztst[] = + { + D3D11_COMPARISON_NEVER, + D3D11_COMPARISON_ALWAYS, + D3D11_COMPARISON_GREATER_EQUAL, + D3D11_COMPARISON_GREATER + }; + + dsd.DepthEnable = dssel.zte; + dsd.DepthWriteMask = dssel.zwe ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; + dsd.DepthFunc = ztst[dssel.ztst]; + } + + CComPtr dss; + + hr = (*m_dev)->CreateDepthStencilState(&dsd, &dss); + + m_om_dss[dssel] = dss; + + i = m_om_dss.find(dssel); + } + + m_dev->OMSetDepthStencilState((*i).second, 1); + + hash_map >::const_iterator j = m_om_bs.find(bsel); + + if(j == m_om_bs.end()) + { + D3D11_BLEND_DESC bd; + + memset(&bd, 0, sizeof(bd)); + + bd.RenderTarget[0].BlendEnable = bsel.abe; + + if(bsel.abe) + { + // (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0 + + static const struct {int bogus; D3D11_BLEND_OP op; D3D11_BLEND src, dst;} map[3*3*3*3] = + { + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {1, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_SRC1_ALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_INV_SRC1_ALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As) + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_SRC1_ALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As + {1, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_DEST_ALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad) + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_DEST_ALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad + {1, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_BLEND_FACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F) + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_BLEND_FACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F + {1, D3D11_BLEND_OP_ADD, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1) + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As + {1, D3D11_BLEND_OP_ADD, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1) + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad + {1, D3D11_BLEND_OP_ADD, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1) + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_INV_SRC1_ALPHA, D3D11_BLEND_SRC1_ALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As) + {1, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_SRC1_ALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_SRC1_ALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_INV_DEST_ALPHA, D3D11_BLEND_DEST_ALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad) + {1, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_DEST_ALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_DEST_ALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_BLEND_FACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F) + {1, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_BLEND_FACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_BLEND_FACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_SRC1_ALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As + {2, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_COLOR, D3D11_BLEND_SRC1_ALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_SRC1_ALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_DEST_ALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad + {2, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_COLOR, D3D11_BLEND_DEST_ALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad) + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_DEST_ALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_BLEND_FACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F + {2, D3D11_BLEND_OP_ADD, D3D11_BLEND_DEST_COLOR, D3D11_BLEND_BLEND_FACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F) + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_BLEND_FACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_INV_SRC1_ALPHA, D3D11_BLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As) + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_INV_DEST_ALPHA, D3D11_BLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad) + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F) + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F + {0, D3D11_BLEND_OP_REV_SUBTRACT, D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_ONE, D3D11_BLEND_SRC1_ALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_INV_SRC1_ALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As) + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_ZERO, D3D11_BLEND_SRC1_ALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_ONE, D3D11_BLEND_DEST_ALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_INV_DEST_ALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad) + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_ONE, D3D11_BLEND_DEST_ALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_ONE, D3D11_BLEND_BLEND_FACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_INV_BLEND_FACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F) + {0, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_ONE, D3D11_BLEND_BLEND_FACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ONE, D3D11_BLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd + {0, D3D11_BLEND_OP_ADD, D3D11_BLEND_ZERO, D3D11_BLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0 + }; + + // bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021 + + // tricky: 1201, 1211, 1221 + // + // Source.rgb = float3(1, 1, 1); + // 1201 Cd*(1 + As) => Source * Dest color + Dest * Source1 alpha + // 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha + // 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor + + int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d; + + bd.RenderTarget[0].BlendOp = map[i].op; + bd.RenderTarget[0].SrcBlend = map[i].src; + bd.RenderTarget[0].DestBlend = map[i].dst; + bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + + if(map[i].bogus == 1) + { + ASSERT(0); + + (bsel.a == 0 ? bd.RenderTarget[0].SrcBlend : bd.RenderTarget[0].DestBlend) = D3D11_BLEND_ONE; + } + } + + if(bsel.wr) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_RED; + if(bsel.wg) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_GREEN; + if(bsel.wb) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_BLUE; + if(bsel.wa) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; + + CComPtr bs; + + hr = (*m_dev)->CreateBlendState(&bd, &bs); + + m_om_bs[bsel] = bs; + + j = m_om_bs.find(bsel); + } + + m_dev->OMSetBlendState((*j).second, bf); +} + +void GSTextureFX11::Draw() +{ + m_dev->DrawPrimitive(); +} diff --git a/plugins/GSdx/GSTextureFX11.h b/plugins/GSdx/GSTextureFX11.h new file mode 100644 index 0000000000..e64b9349ab --- /dev/null +++ b/plugins/GSdx/GSTextureFX11.h @@ -0,0 +1,240 @@ +/* + * 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 "GSDevice11.h" + +class GSTextureFX11 +{ +public: + #pragma pack(push, 1) + + __declspec(align(16)) struct VSConstantBuffer + { + GSVector4 VertexScale; + GSVector4 VertexOffset; + GSVector2 TextureScale; + float _pad[2]; + + struct VSConstantBuffer() {memset(this, 0, sizeof(*this));} + + __forceinline bool Update(const VSConstantBuffer* cb) + { + GSVector4i* a = (GSVector4i*)this; + GSVector4i* b = (GSVector4i*)cb; + + GSVector4i b0 = b[0]; + GSVector4i b1 = b[1]; + GSVector4i b2 = b[2]; + + if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2)).alltrue()) + { + a[0] = b0; + a[1] = b1; + a[2] = b2; + + return true; + } + + return false; + } + }; + + union VSSelector + { + struct + { + uint32 bppz:2; + uint32 tme:1; + uint32 fst:1; + uint32 prim:3; + }; + + uint32 key; + + operator uint32() {return key & 0x7f;} + }; + + __declspec(align(16)) struct PSConstantBuffer + { + GSVector4 FogColor_AREF; + GSVector4 HalfTexel; + GSVector4 WH_TA; + GSVector4 MinMax; + GSVector4 MinMaxF; + GSVector4i MskFix; + + struct PSConstantBuffer() {memset(this, 0, sizeof(*this));} + + __forceinline bool Update(const PSConstantBuffer* cb) + { + GSVector4i* a = (GSVector4i*)this; + GSVector4i* b = (GSVector4i*)cb; + + GSVector4i b0 = b[0]; + GSVector4i b1 = b[1]; + GSVector4i b2 = b[2]; + GSVector4i b3 = b[3]; + GSVector4i b4 = b[4]; + GSVector4i b5 = b[5]; + + if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2) & (a[3] == b3) & (a[4] == b4) & (a[5] == b5)).alltrue()) + { + a[0] = b0; + a[1] = b1; + a[2] = b2; + a[3] = b3; + a[4] = b4; + a[5] = b5; + + return true; + } + + return false; + } + }; + + union GSSelector + { + struct + { + uint32 iip:1; + uint32 prim:2; + }; + + uint32 key; + + operator uint32() {return key & 0x7;} + }; + + union PSSelector + { + struct + { + uint32 fst:1; + uint32 wms:2; + uint32 wmt:2; + uint32 bpp:3; + uint32 aem:1; + uint32 tfx:3; + uint32 tcc:1; + uint32 ate:1; + uint32 atst:3; + uint32 fog:1; + uint32 clr1:1; + uint32 fba:1; + uint32 aout:1; + uint32 ltf:1; + }; + + uint32 key; + + operator uint32() {return key & 0x3fffff;} + }; + + union PSSamplerSelector + { + struct + { + uint32 tau:1; + uint32 tav:1; + uint32 ltf:1; + }; + + uint32 key; + + operator uint32() {return key & 0x7;} + }; + + union OMDepthStencilSelector + { + struct + { + uint32 zte:1; + uint32 ztst:2; + uint32 zwe:1; + uint32 date:1; + }; + + uint32 key; + + operator uint32() {return key & 0x1f;} + }; + + union OMBlendSelector + { + struct + { + uint32 abe:1; + uint32 a:2; + uint32 b:2; + uint32 c:2; + uint32 d:2; + uint32 wr:1; + uint32 wg:1; + uint32 wb:1; + uint32 wa:1; + }; + + uint32 key; + + operator uint32() {return key & 0x1fff;} + }; + + #pragma pack(pop) + +private: + GSDevice11* m_dev; + CComPtr m_il; + 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; + hash_map > m_om_dss; + hash_map > m_om_bs; + + CComPtr m_vb, m_vb_old; + int m_vb_max; + int m_vb_start; + int m_vb_count; + + VSConstantBuffer m_vs_cb_cache; + PSConstantBuffer m_ps_cb_cache; + +public: + GSTextureFX11(); + + bool Create(GSDevice11* dev); + + bool SetupIA(const GSVertexHW11* vertices, int count, D3D11_PRIMITIVE_TOPOLOGY prim); + bool SetupVS(VSSelector sel, const VSConstantBuffer* cb); + bool SetupGS(GSSelector sel); + bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, GSTexture* tex, GSTexture* pal); + void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel); + void SetupRS(int w, int h, const GSVector4i& scissor); + void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, GSTexture* rt, GSTexture* ds); + void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf); + void Draw(); +};