GSdx: another useless revision...

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1405 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gabest11 2009-06-19 20:31:36 +00:00
parent 6ef94cc707
commit 191a3d0c7e
10 changed files with 3050 additions and 0 deletions

870
plugins/GSdx/GSDevice11.cpp Normal file
View File

@ -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<ID3D11Texture2D> 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<ID3D11Texture2D> 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<D3D11_SHADER_MACRO> m;
PrepareShaderMacro(m, macro, m_shader.model.c_str());
CComPtr<ID3D11Blob> 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<D3D11_SHADER_MACRO> m;
PrepareShaderMacro(m, macro, m_shader.model.c_str());
CComPtr<ID3D11Blob> 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<D3D11_SHADER_MACRO> m;
PrepareShaderMacro(m, macro, m_shader.model.c_str());
CComPtr<ID3D10Blob> 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;
}

147
plugins/GSdx/GSDevice11.h Normal file
View File

@ -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<ID3D11Device> m_dev;
CComPtr<ID3D11DeviceContext> m_ctx;
CComPtr<IDXGISwapChain> m_swapchain;
struct {string model, vs, gs, ps;} m_shader;
struct
{
CComPtr<ID3D11Buffer> vb, vb_old;
size_t stride, start, count, limit;
} m_vertices;
public: // TODO
CComPtr<ID3D11RasterizerState> m_rs;
struct
{
CComPtr<ID3D11InputLayout> il;
CComPtr<ID3D11VertexShader> vs;
CComPtr<ID3D11PixelShader> ps[7];
CComPtr<ID3D11SamplerState> ln;
CComPtr<ID3D11SamplerState> pt;
CComPtr<ID3D11DepthStencilState> dss;
CComPtr<ID3D11BlendState> bs;
} m_convert;
struct
{
CComPtr<ID3D11PixelShader> ps[2];
CComPtr<ID3D11Buffer> cb;
CComPtr<ID3D11BlendState> bs;
} m_merge;
struct
{
CComPtr<ID3D11PixelShader> ps[4];
CComPtr<ID3D11Buffer> 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);
};

View File

@ -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<GSVertexHW11>(base, mt, irq, new GSDevice11(), new GSTextureCache11(this))
{
InitVertexKick<GSRendererHW11>();
}
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<uint32 prim, uint32 tme, uint32 fst>
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<prim>(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);
}
}

View File

@ -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<GSVertexHW11>
{
bool WrapZ(uint32 maxz);
protected:
GSTextureFX11 m_tfx;
void Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex);
struct
{
CComPtr<ID3D11DepthStencilState> dss;
CComPtr<ID3D11BlendState> bs;
} m_date;
void SetupDATE(GSTexture* rt, GSTexture* ds);
public:
GSRendererHW11(uint8* base, bool mt, void (*irq)());
bool Create(const string& title);
template<uint32 prim, uint32 tme, uint32 fst> void VertexKick(bool skip);
};

View File

@ -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<ID3D11Resource> 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<ID3D11Texture2D> 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;
}

View File

@ -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<ID3D11Device> m_dev;
CComPtr<ID3D11DeviceContext> m_ctx;
CComPtr<ID3D11Texture2D> m_texture;
D3D11_TEXTURE2D_DESC m_desc;
CComPtr<ID3D11ShaderResourceView> m_srv;
CComPtr<ID3D11RenderTargetView> m_rtv;
CComPtr<ID3D11DepthStencilView> 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*();
};

View File

@ -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;
}

View File

@ -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);
};

View File

@ -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<uint32, CComPtr<ID3D11VertexShader> >::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<ID3D11InputLayout> il;
CComPtr<ID3D11VertexShader> 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<uint32, CComPtr<ID3D11GeometryShader> >::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<uint32, CComPtr<ID3D11PixelShader> >::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<ID3D11PixelShader> 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<uint32, CComPtr<ID3D11SamplerState> >::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<uint32, CComPtr<ID3D11DepthStencilState> >::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<ID3D11DepthStencilState> 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<uint32, CComPtr<ID3D11BlendState> >::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<ID3D11BlendState> 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();
}

View File

@ -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<ID3D11InputLayout> m_il;
hash_map<uint32, CComPtr<ID3D11VertexShader> > m_vs;
CComPtr<ID3D11Buffer> m_vs_cb;
hash_map<uint32, CComPtr<ID3D11GeometryShader> > m_gs;
hash_map<uint32, CComPtr<ID3D11PixelShader> > m_ps;
CComPtr<ID3D11Buffer> m_ps_cb;
hash_map<uint32, CComPtr<ID3D11SamplerState> > m_ps_ss;
CComPtr<ID3D11SamplerState> m_palette_ss;
hash_map<uint32, CComPtr<ID3D11DepthStencilState> > m_om_dss;
hash_map<uint32, CComPtr<ID3D11BlendState> > m_om_bs;
CComPtr<ID3D11Buffer> 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();
};