diff --git a/plugins/GSdx/GSDevice10.cpp b/plugins/GSdx/GSDevice10.cpp index 255ff83870..71235cb092 100644 --- a/plugins/GSdx/GSDevice10.cpp +++ b/plugins/GSdx/GSDevice10.cpp @@ -287,10 +287,12 @@ bool GSDevice10::Reset(int w, int h) 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(ID3D10Texture2D), (void**)&backbuffer); - m_backbuffer = new GSTexture10(backbuffer); + if(!FAILED(m_swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&backbuffer))) + { + m_backbuffer = new GSTexture10(backbuffer); + } } return true; diff --git a/plugins/GSdx/GSDevice11.cpp b/plugins/GSdx/GSDevice11.cpp index b393059eb7..08a8167ab6 100644 --- a/plugins/GSdx/GSDevice11.cpp +++ b/plugins/GSdx/GSDevice11.cpp @@ -1,973 +1,975 @@ -/* - * 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() -{ - memset(&m_state, 0, sizeof(m_state)); - memset(&m_vs_cb_cache, 0, sizeof(m_vs_cb_cache)); - memset(&m_ps_cb_cache, 0, sizeof(m_ps_cb_cache)); - - m_state.topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; - m_state.bf = -1; -} - -GSDevice11::~GSDevice11() -{ -} - -bool GSDevice11::Create(GSWnd* wnd) -{ - if(!__super::Create(wnd)) - { - return false; - } - - HRESULT hr = E_FAIL; - - 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 = D3D11_CREATE_DEVICE_SINGLETHREADED; - -#ifdef DEBUG - flags |= D3D11_CREATE_DEVICE_DEBUG; -#endif - - D3D_FEATURE_LEVEL levels[] = - { - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - }; - - D3D_FEATURE_LEVEL level; - - hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels, countof(levels), D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &level, &m_ctx); - // hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &level, &m_ctx); - - if(FAILED(hr)) return false; - - if(!SetFeatureLevel(level, true)) - { - 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)); - - // msaa - - for(uint32 i = 2; i <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) - { - uint32 quality[2] = {0, 0}; - - if(SUCCEEDED(m_dev->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, i, &quality[0])) && quality[0] > 0 - && SUCCEEDED(m_dev->CheckMultisampleQualityLevels(DXGI_FORMAT_D32_FLOAT_S8X24_UINT, i, &quality[1])) && quality[1] > 0) - { - m_msaa_desc.Count = i; - m_msaa_desc.Quality = std::min(quality[0] - 1, quality[1] - 1); - - if(i >= m_msaa) break; - } - } - - // 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 = true; - 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); - - // - - CreateTextureFX(); - - // - - 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; - - m_dev->CreateDepthStencilState(&dsd, &m_date.dss); - - D3D11_BLEND_DESC blend; - - memset(&blend, 0, sizeof(blend)); - - m_dev->CreateBlendState(&blend, &m_date.bs); - - // - - if(m_wnd->IsManaged()) - { - SetExclusive( !theApp.GetConfig("windowed", 1) ); - } - - return true; -} - -bool GSDevice11::Reset(int w, int h) -{ - if(!__super::Reset(w, h)) - return false; - - if(m_swapchain) - { - 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::SetExclusive(bool isExcl) -{ - if(!m_swapchain) return; - - // TODO : Support for alternative display modes, by finishing this code below: - // Video mode info should be pulled form config/ini. - - /*DXGI_MODE_DESC desc; - memset(&desc, 0, sizeof(desc)); - desc.RefreshRate = 0; // must be zero for best results. - - m_swapchain->ResizeTarget(&desc); - */ - - HRESULT hr = m_swapchain->SetFullscreenState( isExcl, NULL ); - if(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) - fprintf(stderr, "(GSdx10) SetExclusive(%s) failed; request unavailable.", isExcl ? "true" : "false"); -} - -void GSDevice11::Flip() -{ - m_swapchain->Present(m_vsync, 0); -} - -void GSDevice11::DrawPrimitive() -{ - m_ctx->Draw(m_vertices.count, m_vertices.start); -} - -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, bool msaa, 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; - - if(msaa) - { - desc.SampleDesc = m_msaa_desc; - } - - 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, bool msaa, int format) -{ - return __super::CreateRenderTarget(w, h, msaa, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); -} - -GSTexture* GSDevice11::CreateDepthStencil(int w, int h, bool msaa, int format) -{ - return __super::CreateDepthStencil(w, h, msaa, 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::Resolve(GSTexture* t) -{ - 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; -} - -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, 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; -} - -void GSDevice11::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r) -{ - D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; - - m_ctx->CopySubresourceRegion(*(GSTexture11*)dt, 0, r.left, r.top, 0, *(GSTexture11*)st, 0, &box); -} - -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); - - // - - DrawPrimitive(); - - // - - EndScene(); - - PSSetShaderResources(NULL, NULL); -} - -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::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1 (&iaVertices)[4], bool datm) -{ - const GSVector2i& size = rt->GetSize(); - - if(GSTexture* t = CreateRenderTarget(size.x, size.y, rt->IsMSAA())) - { - // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows - - BeginScene(); - - ClearStencil(ds, 0); - - // om - - OMSetDepthStencilState(m_date.dss, 1); - OMSetBlendState(m_date.bs, 0); - OMSetRenderTargets(t, ds); - - // ia - - IASetVertexBuffer(iaVertices, sizeof(iaVertices[0]), countof(iaVertices)); - IASetInputLayout(m_convert.il); - IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - // vs - - VSSetShader(m_convert.vs, NULL); - - // gs - - GSSetShader(NULL); - - // ps - - GSTexture* rt2 = rt->IsMSAA() ? Resolve(rt) : rt; - - PSSetShaderResources(rt2, NULL); - PSSetShader(m_convert.ps[datm ? 2 : 3], NULL); - PSSetSamplerState(m_convert.pt, NULL); - - // - - DrawPrimitive(); - - // - - EndScene(); - - Recycle(t); - - if(rt2 != rt) Recycle(rt2); - } -} - -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_vb_old = m_vb; - m_vb = NULL; - - m_vertices.start = 0; - m_vertices.count = 0; - m_vertices.limit = std::max(count * 3 / 2, 10000); - } - - if(m_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_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_vb, 0, type, 0, &m))) - { - GSVector4i::storent((uint8*)m.pData + m_vertices.start * stride, vertices, count * stride); - - m_ctx->Unmap(m_vb, 0); - } - - m_vertices.count = count; - m_vertices.stride = stride; - - IASetVertexBuffer(m_vb, stride); -} - -void GSDevice11::IASetVertexBuffer(ID3D11Buffer* vb, size_t stride) -{ - if(m_state.vb != vb || m_state.vb_stride != stride) - { - m_state.vb = vb; - m_state.vb_stride = stride; - - uint32 offset = 0; - - m_ctx->IASetVertexBuffers(0, 1, &vb, &stride, &offset); - } -} - -void GSDevice11::IASetInputLayout(ID3D11InputLayout* layout) -{ - if(m_state.layout != layout) - { - m_state.layout = layout; - - m_ctx->IASetInputLayout(layout); - } -} - -void GSDevice11::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology) -{ - if(m_state.topology != topology) - { - m_state.topology = topology; - - m_ctx->IASetPrimitiveTopology(topology); - } -} - -void GSDevice11::VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb) -{ - if(m_state.vs != vs) - { - m_state.vs = vs; - - m_ctx->VSSetShader(vs, NULL, 0); - } - - if(m_state.vs_cb != vs_cb) - { - m_state.vs_cb = vs_cb; - - m_ctx->VSSetConstantBuffers(0, 1, &vs_cb); - } -} - -void GSDevice11::GSSetShader(ID3D11GeometryShader* gs) -{ - if(m_state.gs != gs) - { - m_state.gs = gs; - - m_ctx->GSSetShader(gs, NULL, 0); - } -} - -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_state.ps_srv[0] != srv0 || m_state.ps_srv[1] != srv1) - { - m_state.ps_srv[0] = srv0; - m_state.ps_srv[1] = srv1; - - ID3D11ShaderResourceView* srvs[] = {srv0, srv1}; - - m_ctx->PSSetShaderResources(0, 2, srvs); - } -} - -void GSDevice11::PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb) -{ - if(m_state.ps != ps) - { - m_state.ps = ps; - - m_ctx->PSSetShader(ps, NULL, 0); - } - - if(m_state.ps_cb != ps_cb) - { - m_state.ps_cb = ps_cb; - - m_ctx->PSSetConstantBuffers(0, 1, &ps_cb); - } -} - -void GSDevice11::PSSetSamplerState(ID3D11SamplerState* ss0, ID3D11SamplerState* ss1) -{ - if(m_state.ps_ss[0] != ss0 || m_state.ps_ss[1] != ss1) - { - m_state.ps_ss[0] = ss0; - m_state.ps_ss[1] = ss1; - - ID3D11SamplerState* sss[] = {ss0, ss1}; - - m_ctx->PSSetSamplers(0, 2, sss); - } -} - -void GSDevice11::OMSetDepthStencilState(ID3D11DepthStencilState* dss, uint8 sref) -{ - if(m_state.dss != dss || m_state.sref != sref) - { - m_state.dss = dss; - m_state.sref = sref; - - m_ctx->OMSetDepthStencilState(dss, sref); - } -} - -void GSDevice11::OMSetBlendState(ID3D11BlendState* bs, float bf) -{ - 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); - } -} - -void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor) -{ - 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); - } - - 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 = rt->GetWidth(); - vp.Height = rt->GetHeight(); - vp.MinDepth = 0.0f; - vp.MaxDepth = 1.0f; - - m_ctx->RSSetViewports(1, &vp); - } - - GSVector4i r = scissor ? *scissor : GSVector4i(rt->GetSize()).zwxy(); - - if(!m_state.scissor.eq(r)) - { - m_state.scissor = r; - - m_ctx->RSSetScissorRects(1, r); - } -} - -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); - - 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); - - 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); - - 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; -} +/* + * 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() +{ + memset(&m_state, 0, sizeof(m_state)); + memset(&m_vs_cb_cache, 0, sizeof(m_vs_cb_cache)); + memset(&m_ps_cb_cache, 0, sizeof(m_ps_cb_cache)); + + m_state.topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED; + m_state.bf = -1; +} + +GSDevice11::~GSDevice11() +{ +} + +bool GSDevice11::Create(GSWnd* wnd) +{ + if(!__super::Create(wnd)) + { + return false; + } + + HRESULT hr = E_FAIL; + + 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 = D3D11_CREATE_DEVICE_SINGLETHREADED; + +#ifdef DEBUG + flags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + D3D_FEATURE_LEVEL levels[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + + D3D_FEATURE_LEVEL level; + + hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags, levels, countof(levels), D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &level, &m_ctx); + // hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, flags, NULL, 0, D3D11_SDK_VERSION, &scd, &m_swapchain, &m_dev, &level, &m_ctx); + + if(FAILED(hr)) return false; + + if(!SetFeatureLevel(level, true)) + { + 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)); + + // msaa + + for(uint32 i = 2; i <= D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; i++) + { + uint32 quality[2] = {0, 0}; + + if(SUCCEEDED(m_dev->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, i, &quality[0])) && quality[0] > 0 + && SUCCEEDED(m_dev->CheckMultisampleQualityLevels(DXGI_FORMAT_D32_FLOAT_S8X24_UINT, i, &quality[1])) && quality[1] > 0) + { + m_msaa_desc.Count = i; + m_msaa_desc.Quality = std::min(quality[0] - 1, quality[1] - 1); + + if(i >= m_msaa) break; + } + } + + // 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 = true; + 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); + + // + + CreateTextureFX(); + + // + + 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; + + m_dev->CreateDepthStencilState(&dsd, &m_date.dss); + + D3D11_BLEND_DESC blend; + + memset(&blend, 0, sizeof(blend)); + + m_dev->CreateBlendState(&blend, &m_date.bs); + + // + + if(m_wnd->IsManaged()) + { + SetExclusive( !theApp.GetConfig("windowed", 1) ); + } + + return true; +} + +bool GSDevice11::Reset(int w, int h) +{ + if(!__super::Reset(w, h)) + return false; + + if(m_swapchain) + { + 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; + if(!FAILED(m_swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backbuffer))) + { + m_backbuffer = new GSTexture11(backbuffer); + } + } + + return true; +} + +void GSDevice11::SetExclusive(bool isExcl) +{ + if(!m_swapchain) return; + + // TODO : Support for alternative display modes, by finishing this code below: + // Video mode info should be pulled form config/ini. + + /*DXGI_MODE_DESC desc; + memset(&desc, 0, sizeof(desc)); + desc.RefreshRate = 0; // must be zero for best results. + + m_swapchain->ResizeTarget(&desc); + */ + + HRESULT hr = m_swapchain->SetFullscreenState( isExcl, NULL ); + if(hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) + fprintf(stderr, "(GSdx10) SetExclusive(%s) failed; request unavailable.", isExcl ? "true" : "false"); +} + +void GSDevice11::Flip() +{ + m_swapchain->Present(m_vsync, 0); +} + +void GSDevice11::DrawPrimitive() +{ + m_ctx->Draw(m_vertices.count, m_vertices.start); +} + +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, bool msaa, 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; + + if(msaa) + { + desc.SampleDesc = m_msaa_desc; + } + + 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, bool msaa, int format) +{ + return __super::CreateRenderTarget(w, h, msaa, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM); +} + +GSTexture* GSDevice11::CreateDepthStencil(int w, int h, bool msaa, int format) +{ + return __super::CreateDepthStencil(w, h, msaa, 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::Resolve(GSTexture* t) +{ + 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; +} + +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, 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; +} + +void GSDevice11::CopyRect(GSTexture* st, GSTexture* dt, const GSVector4i& r) +{ + D3D11_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1}; + + m_ctx->CopySubresourceRegion(*(GSTexture11*)dt, 0, r.left, r.top, 0, *(GSTexture11*)st, 0, &box); +} + +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); + + // + + DrawPrimitive(); + + // + + EndScene(); + + PSSetShaderResources(NULL, NULL); +} + +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::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1 (&iaVertices)[4], bool datm) +{ + const GSVector2i& size = rt->GetSize(); + + if(GSTexture* t = CreateRenderTarget(size.x, size.y, rt->IsMSAA())) + { + // sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows + + BeginScene(); + + ClearStencil(ds, 0); + + // om + + OMSetDepthStencilState(m_date.dss, 1); + OMSetBlendState(m_date.bs, 0); + OMSetRenderTargets(t, ds); + + // ia + + IASetVertexBuffer(iaVertices, sizeof(iaVertices[0]), countof(iaVertices)); + IASetInputLayout(m_convert.il); + IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + // vs + + VSSetShader(m_convert.vs, NULL); + + // gs + + GSSetShader(NULL); + + // ps + + GSTexture* rt2 = rt->IsMSAA() ? Resolve(rt) : rt; + + PSSetShaderResources(rt2, NULL); + PSSetShader(m_convert.ps[datm ? 2 : 3], NULL); + PSSetSamplerState(m_convert.pt, NULL); + + // + + DrawPrimitive(); + + // + + EndScene(); + + Recycle(t); + + if(rt2 != rt) Recycle(rt2); + } +} + +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_vb_old = m_vb; + m_vb = NULL; + + m_vertices.start = 0; + m_vertices.count = 0; + m_vertices.limit = std::max(count * 3 / 2, 10000); + } + + if(m_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_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_vb, 0, type, 0, &m))) + { + GSVector4i::storent((uint8*)m.pData + m_vertices.start * stride, vertices, count * stride); + + m_ctx->Unmap(m_vb, 0); + } + + m_vertices.count = count; + m_vertices.stride = stride; + + IASetVertexBuffer(m_vb, stride); +} + +void GSDevice11::IASetVertexBuffer(ID3D11Buffer* vb, size_t stride) +{ + if(m_state.vb != vb || m_state.vb_stride != stride) + { + m_state.vb = vb; + m_state.vb_stride = stride; + + uint32 offset = 0; + + m_ctx->IASetVertexBuffers(0, 1, &vb, &stride, &offset); + } +} + +void GSDevice11::IASetInputLayout(ID3D11InputLayout* layout) +{ + if(m_state.layout != layout) + { + m_state.layout = layout; + + m_ctx->IASetInputLayout(layout); + } +} + +void GSDevice11::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY topology) +{ + if(m_state.topology != topology) + { + m_state.topology = topology; + + m_ctx->IASetPrimitiveTopology(topology); + } +} + +void GSDevice11::VSSetShader(ID3D11VertexShader* vs, ID3D11Buffer* vs_cb) +{ + if(m_state.vs != vs) + { + m_state.vs = vs; + + m_ctx->VSSetShader(vs, NULL, 0); + } + + if(m_state.vs_cb != vs_cb) + { + m_state.vs_cb = vs_cb; + + m_ctx->VSSetConstantBuffers(0, 1, &vs_cb); + } +} + +void GSDevice11::GSSetShader(ID3D11GeometryShader* gs) +{ + if(m_state.gs != gs) + { + m_state.gs = gs; + + m_ctx->GSSetShader(gs, NULL, 0); + } +} + +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_state.ps_srv[0] != srv0 || m_state.ps_srv[1] != srv1) + { + m_state.ps_srv[0] = srv0; + m_state.ps_srv[1] = srv1; + + ID3D11ShaderResourceView* srvs[] = {srv0, srv1}; + + m_ctx->PSSetShaderResources(0, 2, srvs); + } +} + +void GSDevice11::PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb) +{ + if(m_state.ps != ps) + { + m_state.ps = ps; + + m_ctx->PSSetShader(ps, NULL, 0); + } + + if(m_state.ps_cb != ps_cb) + { + m_state.ps_cb = ps_cb; + + m_ctx->PSSetConstantBuffers(0, 1, &ps_cb); + } +} + +void GSDevice11::PSSetSamplerState(ID3D11SamplerState* ss0, ID3D11SamplerState* ss1) +{ + if(m_state.ps_ss[0] != ss0 || m_state.ps_ss[1] != ss1) + { + m_state.ps_ss[0] = ss0; + m_state.ps_ss[1] = ss1; + + ID3D11SamplerState* sss[] = {ss0, ss1}; + + m_ctx->PSSetSamplers(0, 2, sss); + } +} + +void GSDevice11::OMSetDepthStencilState(ID3D11DepthStencilState* dss, uint8 sref) +{ + if(m_state.dss != dss || m_state.sref != sref) + { + m_state.dss = dss; + m_state.sref = sref; + + m_ctx->OMSetDepthStencilState(dss, sref); + } +} + +void GSDevice11::OMSetBlendState(ID3D11BlendState* bs, float bf) +{ + 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); + } +} + +void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor) +{ + 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); + } + + 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 = rt->GetWidth(); + vp.Height = rt->GetHeight(); + vp.MinDepth = 0.0f; + vp.MaxDepth = 1.0f; + + m_ctx->RSSetViewports(1, &vp); + } + + GSVector4i r = scissor ? *scissor : GSVector4i(rt->GetSize()).zwxy(); + + if(!m_state.scissor.eq(r)) + { + m_state.scissor = r; + + m_ctx->RSSetScissorRects(1, r); + } +} + +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); + + 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); + + 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); + + 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; +}