1411 lines
50 KiB
C++
1411 lines
50 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include <xenia/gpu/d3d11/d3d11_graphics_driver.h>
|
|
|
|
#include <xenia/gpu/gpu-private.h>
|
|
#include <xenia/gpu/d3d11/d3d11_geometry_shader.h>
|
|
#include <xenia/gpu/d3d11/d3d11_shader.h>
|
|
#include <xenia/gpu/d3d11/d3d11_shader_cache.h>
|
|
|
|
|
|
using namespace xe;
|
|
using namespace xe::gpu;
|
|
using namespace xe::gpu::d3d11;
|
|
using namespace xe::gpu::xenos;
|
|
|
|
|
|
D3D11GraphicsDriver::D3D11GraphicsDriver(
|
|
Memory* memory, IDXGISwapChain* swap_chain, ID3D11Device* device) :
|
|
GraphicsDriver(memory) {
|
|
swap_chain_ = swap_chain;
|
|
swap_chain_->AddRef();
|
|
device_ = device;
|
|
device_->AddRef();
|
|
device_->GetImmediateContext(&context_);
|
|
shader_cache_ = new D3D11ShaderCache(device_);
|
|
|
|
xe_zero_struct(&state_, sizeof(state_));
|
|
|
|
xe_zero_struct(&render_targets_, sizeof(render_targets_));
|
|
|
|
HRESULT hr;
|
|
D3D11_BUFFER_DESC buffer_desc;
|
|
xe_zero_struct(&buffer_desc, sizeof(buffer_desc));
|
|
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
|
|
buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
|
|
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
buffer_desc.ByteWidth = (512 * 4) * sizeof(float);
|
|
hr = device_->CreateBuffer(
|
|
&buffer_desc, NULL, &state_.constant_buffers.float_constants);
|
|
buffer_desc.ByteWidth = (8) * sizeof(int);
|
|
hr = device_->CreateBuffer(
|
|
&buffer_desc, NULL, &state_.constant_buffers.bool_constants);
|
|
buffer_desc.ByteWidth = (32) * sizeof(int);
|
|
hr = device_->CreateBuffer(
|
|
&buffer_desc, NULL, &state_.constant_buffers.loop_constants);
|
|
buffer_desc.ByteWidth = (32) * sizeof(int);
|
|
hr = device_->CreateBuffer(
|
|
&buffer_desc, NULL, &state_.constant_buffers.vs_consts);
|
|
buffer_desc.ByteWidth = (32) * sizeof(int);
|
|
hr = device_->CreateBuffer(
|
|
&buffer_desc, NULL, &state_.constant_buffers.gs_consts);
|
|
|
|
// TODO(benvanik): pattern?
|
|
invalid_texture_view_ = NULL;
|
|
|
|
D3D11_SAMPLER_DESC sampler_desc;
|
|
xe_zero_struct(&sampler_desc, sizeof(sampler_desc));
|
|
sampler_desc.Filter;
|
|
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.MipLODBias;
|
|
sampler_desc.MaxAnisotropy = 1;
|
|
sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
|
sampler_desc.BorderColor[0];
|
|
sampler_desc.BorderColor[1];
|
|
sampler_desc.BorderColor[2];
|
|
sampler_desc.BorderColor[3];
|
|
sampler_desc.MinLOD;
|
|
sampler_desc.MaxLOD;
|
|
hr = device_->CreateSamplerState(
|
|
&sampler_desc, &invalid_texture_sampler_state_);
|
|
if (FAILED(hr)) {
|
|
XEFATAL("D3D11: unable to create invalid sampler state");
|
|
}
|
|
}
|
|
|
|
D3D11GraphicsDriver::~D3D11GraphicsDriver() {
|
|
RebuildRenderTargets(0, 0);
|
|
for (size_t n = 0; n < XECOUNT(state_.texture_fetchers); n++) {
|
|
XESAFERELEASE(state_.texture_fetchers[n].view);
|
|
}
|
|
XESAFERELEASE(state_.constant_buffers.float_constants);
|
|
XESAFERELEASE(state_.constant_buffers.bool_constants);
|
|
XESAFERELEASE(state_.constant_buffers.loop_constants);
|
|
XESAFERELEASE(state_.constant_buffers.vs_consts);
|
|
XESAFERELEASE(state_.constant_buffers.gs_consts);
|
|
XESAFERELEASE(invalid_texture_view_);
|
|
XESAFERELEASE(invalid_texture_sampler_state_);
|
|
delete shader_cache_;
|
|
XESAFERELEASE(context_);
|
|
XESAFERELEASE(device_);
|
|
XESAFERELEASE(swap_chain_);
|
|
}
|
|
|
|
void D3D11GraphicsDriver::Initialize() {
|
|
}
|
|
|
|
void D3D11GraphicsDriver::InvalidateState(
|
|
uint32_t mask) {
|
|
if (mask == XE_GPU_INVALIDATE_MASK_ALL) {
|
|
XELOGGPU("D3D11: (invalidate all)");
|
|
}
|
|
if (mask & XE_GPU_INVALIDATE_MASK_VERTEX_SHADER) {
|
|
XELOGGPU("D3D11: invalidate vertex shader");
|
|
}
|
|
if (mask & XE_GPU_INVALIDATE_MASK_PIXEL_SHADER) {
|
|
XELOGGPU("D3D11: invalidate pixel shader");
|
|
}
|
|
}
|
|
|
|
void D3D11GraphicsDriver::SetShader(
|
|
XE_GPU_SHADER_TYPE type,
|
|
uint32_t address,
|
|
uint32_t start,
|
|
uint32_t length) {
|
|
// Find or create shader in the cache.
|
|
uint8_t* p = memory_->Translate(address);
|
|
Shader* shader = shader_cache_->FindOrCreate(
|
|
type, p, length);
|
|
|
|
// Disassemble.
|
|
const char* source = shader->disasm_src();
|
|
if (!source) {
|
|
source = "<failed to disassemble>";
|
|
}
|
|
XELOGGPU("D3D11: set shader %d at %0.8X (%db):\n%s",
|
|
type, address, length, source);
|
|
|
|
// Stash for later.
|
|
switch (type) {
|
|
case XE_GPU_SHADER_TYPE_VERTEX:
|
|
state_.vertex_shader = (D3D11VertexShader*)shader;
|
|
break;
|
|
case XE_GPU_SHADER_TYPE_PIXEL:
|
|
state_.pixel_shader = (D3D11PixelShader*)shader;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int D3D11GraphicsDriver::SetupDraw(XE_GPU_PRIMITIVE_TYPE prim_type) {
|
|
RegisterFile& rf = register_file_;
|
|
|
|
// Ignore copies.
|
|
uint32_t enable_mode = rf.values[XE_GPU_REG_RB_MODECONTROL].u32 & 0x7;
|
|
if (enable_mode != 4) {
|
|
XELOGW("D3D11: ignoring draw with enable mode %d", enable_mode);
|
|
return 1;
|
|
}
|
|
|
|
uint32_t state_overrides = 0;
|
|
if (prim_type == XE_GPU_PRIMITIVE_TYPE_RECTANGLE_LIST) {
|
|
// Rect lists aren't culled. There may be other things they skip too.
|
|
state_overrides |= STATE_OVERRIDE_DISABLE_CULLING;
|
|
}
|
|
|
|
// Misc state.
|
|
if (UpdateState(state_overrides)) {
|
|
return 1;
|
|
}
|
|
|
|
// Build constant buffers.
|
|
if (UpdateConstantBuffers()) {
|
|
return 1;
|
|
}
|
|
|
|
// Bind shaders.
|
|
if (BindShaders()) {
|
|
return 1;
|
|
}
|
|
|
|
// Switch primitive topology.
|
|
// Some are unsupported on D3D11 and must be emulated.
|
|
D3D11_PRIMITIVE_TOPOLOGY primitive_topology;
|
|
D3D11GeometryShader* geometry_shader = NULL;
|
|
switch (prim_type) {
|
|
case XE_GPU_PRIMITIVE_TYPE_POINT_LIST:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
|
if (state_.vertex_shader) {
|
|
if (state_.vertex_shader->DemandGeometryShader(
|
|
D3D11VertexShader::POINT_SPRITE_SHADER, &geometry_shader)) {
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
case XE_GPU_PRIMITIVE_TYPE_LINE_LIST:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST;
|
|
break;
|
|
case XE_GPU_PRIMITIVE_TYPE_LINE_STRIP:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP;
|
|
break;
|
|
case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_LIST:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
|
break;
|
|
case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_STRIP:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
|
break;
|
|
case XE_GPU_PRIMITIVE_TYPE_RECTANGLE_LIST:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
|
if (state_.vertex_shader) {
|
|
if (state_.vertex_shader->DemandGeometryShader(
|
|
D3D11VertexShader::RECT_LIST_SHADER, &geometry_shader)) {
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
case XE_GPU_PRIMITIVE_TYPE_QUAD_LIST:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
|
|
if (state_.vertex_shader) {
|
|
if (state_.vertex_shader->DemandGeometryShader(
|
|
D3D11VertexShader::QUAD_LIST_SHADER, &geometry_shader)) {
|
|
return 1;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
case XE_GPU_PRIMITIVE_TYPE_TRIANGLE_FAN:
|
|
case XE_GPU_PRIMITIVE_TYPE_UNKNOWN_07:
|
|
case XE_GPU_PRIMITIVE_TYPE_LINE_LOOP:
|
|
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
|
|
XELOGE("D3D11: unsupported primitive type %d", prim_type);
|
|
break;
|
|
}
|
|
context_->IASetPrimitiveTopology(primitive_topology);
|
|
|
|
if (geometry_shader) {
|
|
context_->GSSetShader(geometry_shader->handle(), NULL, NULL);
|
|
context_->GSSetConstantBuffers(
|
|
0, 1, &state_.constant_buffers.gs_consts);
|
|
} else {
|
|
context_->GSSetShader(NULL, NULL, NULL);
|
|
}
|
|
|
|
// Setup all fetchers (vertices/textures).
|
|
if (PrepareFetchers()) {
|
|
return 1;
|
|
}
|
|
|
|
// All ready to draw (except index buffer)!
|
|
|
|
return 0;
|
|
}
|
|
|
|
void D3D11GraphicsDriver::DrawIndexBuffer(
|
|
XE_GPU_PRIMITIVE_TYPE prim_type,
|
|
bool index_32bit, uint32_t index_count,
|
|
uint32_t index_base, uint32_t index_size, uint32_t endianness) {
|
|
RegisterFile& rf = register_file_;
|
|
|
|
XELOGGPU("D3D11: draw indexed %d (%d indicies) from %.8X",
|
|
prim_type, index_count, index_base);
|
|
|
|
// Setup shaders/etc.
|
|
if (SetupDraw(prim_type)) {
|
|
return;
|
|
}
|
|
|
|
// Setup index buffer.
|
|
if (PrepareIndexBuffer(
|
|
index_32bit, index_count, index_base, index_size, endianness)) {
|
|
return;
|
|
}
|
|
|
|
// Issue draw.
|
|
uint32_t start_index = rf.values[XE_GPU_REG_VGT_INDX_OFFSET].u32;
|
|
uint32_t base_vertex = 0;
|
|
context_->DrawIndexed(index_count, start_index, base_vertex);
|
|
}
|
|
|
|
void D3D11GraphicsDriver::DrawIndexAuto(
|
|
XE_GPU_PRIMITIVE_TYPE prim_type,
|
|
uint32_t index_count) {
|
|
RegisterFile& rf = register_file_;
|
|
|
|
XELOGGPU("D3D11: draw indexed %d (%d indicies)",
|
|
prim_type, index_count);
|
|
|
|
// Setup shaders/etc.
|
|
if (SetupDraw(prim_type)) {
|
|
return;
|
|
}
|
|
|
|
// Issue draw.
|
|
uint32_t start_index = rf.values[XE_GPU_REG_VGT_INDX_OFFSET].u32;
|
|
uint32_t base_vertex = 0;
|
|
//context_->DrawIndexed(index_count, start_index, base_vertex);
|
|
context_->Draw(index_count, 0);
|
|
}
|
|
|
|
int D3D11GraphicsDriver::RebuildRenderTargets(
|
|
uint32_t width, uint32_t height) {
|
|
if (width == render_targets_.width &&
|
|
height == render_targets_.height) {
|
|
// Cached copies are good.
|
|
return 0;
|
|
}
|
|
|
|
// Remove old versions.
|
|
for (int n = 0; n < XECOUNT(render_targets_.color_buffers); n++) {
|
|
auto& cb = render_targets_.color_buffers[n];
|
|
XESAFERELEASE(cb.buffer);
|
|
XESAFERELEASE(cb.color_view_8888);
|
|
}
|
|
XESAFERELEASE(render_targets_.depth_buffer);
|
|
XESAFERELEASE(render_targets_.depth_view_d28s8);
|
|
XESAFERELEASE(render_targets_.depth_view_d28fs8);
|
|
|
|
render_targets_.width = width;
|
|
render_targets_.height = height;
|
|
|
|
if (!width || !height) {
|
|
// This should only happen when cleaning up.
|
|
return 0;
|
|
}
|
|
|
|
for (int n = 0; n < XECOUNT(render_targets_.color_buffers); n++) {
|
|
auto& cb = render_targets_.color_buffers[n];
|
|
D3D11_TEXTURE2D_DESC color_buffer_desc;
|
|
xe_zero_struct(&color_buffer_desc, sizeof(color_buffer_desc));
|
|
color_buffer_desc.Width = width;
|
|
color_buffer_desc.Height = height;
|
|
color_buffer_desc.MipLevels = 1;
|
|
color_buffer_desc.ArraySize = 1;
|
|
color_buffer_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
color_buffer_desc.SampleDesc.Count = 1;
|
|
color_buffer_desc.SampleDesc.Quality = 0;
|
|
color_buffer_desc.Usage = D3D11_USAGE_DEFAULT;
|
|
color_buffer_desc.BindFlags =
|
|
D3D11_BIND_SHADER_RESOURCE |
|
|
D3D11_BIND_RENDER_TARGET;
|
|
color_buffer_desc.CPUAccessFlags = 0;
|
|
color_buffer_desc.MiscFlags = 0;
|
|
device_->CreateTexture2D(
|
|
&color_buffer_desc, NULL, &cb.buffer);
|
|
|
|
D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
|
|
xe_zero_struct(&render_target_view_desc, sizeof(render_target_view_desc));
|
|
render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
|
// render_target_view_desc.Buffer ?
|
|
device_->CreateRenderTargetView(
|
|
cb.buffer,
|
|
&render_target_view_desc,
|
|
&cb.color_view_8888);
|
|
}
|
|
|
|
D3D11_TEXTURE2D_DESC depth_stencil_desc;
|
|
xe_zero_struct(&depth_stencil_desc, sizeof(depth_stencil_desc));
|
|
depth_stencil_desc.Width = width;
|
|
depth_stencil_desc.Height = height;
|
|
depth_stencil_desc.MipLevels = 1;
|
|
depth_stencil_desc.ArraySize = 1;
|
|
depth_stencil_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
depth_stencil_desc.SampleDesc.Count = 1;
|
|
depth_stencil_desc.SampleDesc.Quality = 0;
|
|
depth_stencil_desc.Usage = D3D11_USAGE_DEFAULT;
|
|
depth_stencil_desc.BindFlags =
|
|
D3D11_BIND_DEPTH_STENCIL;
|
|
depth_stencil_desc.CPUAccessFlags = 0;
|
|
depth_stencil_desc.MiscFlags = 0;
|
|
device_->CreateTexture2D(
|
|
&depth_stencil_desc, NULL, &render_targets_.depth_buffer);
|
|
|
|
D3D11_DEPTH_STENCIL_VIEW_DESC depth_stencil_view_desc;
|
|
xe_zero_struct(&depth_stencil_view_desc, sizeof(depth_stencil_view_desc));
|
|
depth_stencil_view_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
depth_stencil_view_desc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
|
depth_stencil_view_desc.Flags = 0;
|
|
device_->CreateDepthStencilView(
|
|
render_targets_.depth_buffer,
|
|
&depth_stencil_view_desc,
|
|
&render_targets_.depth_view_d28s8);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::UpdateState(uint32_t state_overrides) {
|
|
// Most information comes from here:
|
|
// https://chromium.googlesource.com/chromiumos/third_party/mesa/+/6173cc19c45d92ef0b7bc6aa008aa89bb29abbda/src/gallium/drivers/freedreno/freedreno_zsa.c
|
|
// http://cgit.freedesktop.org/mesa/mesa/diff/?id=aac7f06ad843eaa696363e8e9c7781ca30cb4914
|
|
// The only differences so far are extra packets for multiple render targets
|
|
// and a few modes being switched around.
|
|
|
|
RegisterFile& rf = register_file_;
|
|
|
|
uint32_t window_scissor_tl = rf.values[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32;
|
|
uint32_t window_scissor_br = rf.values[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR].u32;
|
|
//uint32_t window_width =
|
|
// (window_scissor_br & 0x7FFF) - (window_scissor_tl & 0x7FFF);
|
|
//uint32_t window_height =
|
|
// ((window_scissor_br >> 16) & 0x7FFF) - ((window_scissor_tl >> 16) & 0x7FFF);
|
|
uint32_t window_width = 1280;
|
|
uint32_t window_height = 720;
|
|
if (RebuildRenderTargets(window_width, window_height)) {
|
|
XELOGE("Unable to rebuild render targets to %d x %d",
|
|
window_width, window_height);
|
|
return 1;
|
|
}
|
|
|
|
// RB_SURFACE_INFO ?
|
|
|
|
// Enable buffers.
|
|
uint32_t enable_mode = rf.values[XE_GPU_REG_RB_MODECONTROL].u32 & 0x7;
|
|
// 4 = color + depth
|
|
// 6 = copy ?
|
|
|
|
// color_info[0-3] has format 8888
|
|
uint32_t color_info[4] = {
|
|
rf.values[XE_GPU_REG_RB_COLOR_INFO].u32,
|
|
rf.values[XE_GPU_REG_RB_COLOR1_INFO].u32,
|
|
rf.values[XE_GPU_REG_RB_COLOR2_INFO].u32,
|
|
rf.values[XE_GPU_REG_RB_COLOR3_INFO].u32,
|
|
};
|
|
ID3D11RenderTargetView* render_target_views[4] = { 0 };
|
|
for (int n = 0; n < XECOUNT(color_info); n++) {
|
|
auto cb = render_targets_.color_buffers[n];
|
|
uint32_t color_format = (color_info[n] >> 16) & 0xF;
|
|
switch (color_format) {
|
|
case 0: // D3DFMT_A8R8G8B8 (or ABGR?)
|
|
case 1:
|
|
render_target_views[n] = cb.color_view_8888;
|
|
break;
|
|
default:
|
|
// Unknown.
|
|
XELOGGPU("Unsupported render target format %d", color_format);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// depth_info has format 24_8
|
|
uint32_t depth_info = rf.values[XE_GPU_REG_RB_DEPTH_INFO].u32;
|
|
uint32_t depth_format = (depth_info >> 16) & 0x1;
|
|
ID3D11DepthStencilView* depth_stencil_view = 0;
|
|
switch (depth_format) {
|
|
case 0: // D3DFMT_D24S8
|
|
depth_stencil_view = render_targets_.depth_view_d28s8;
|
|
break;
|
|
default:
|
|
case 1: // D3DFMT_D24FS8
|
|
//depth_stencil_view = render_targets_.depth_view_d28fs8;
|
|
XELOGGPU("Unsupported depth/stencil format %d", depth_format);
|
|
break;
|
|
}
|
|
// TODO(benvanik): when a game switches does it expect to keep the same
|
|
// depth buffer contents?
|
|
|
|
// TODO(benvanik): only enable the number of valid render targets.
|
|
context_->OMSetRenderTargets(4, render_target_views, depth_stencil_view);
|
|
|
|
// General rasterizer state.
|
|
uint32_t mode_control = rf.values[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32;
|
|
D3D11_RASTERIZER_DESC rasterizer_desc;
|
|
xe_zero_struct(&rasterizer_desc, sizeof(rasterizer_desc));
|
|
rasterizer_desc.FillMode = D3D11_FILL_SOLID; // D3D11_FILL_WIREFRAME;
|
|
switch (mode_control & 0x3) {
|
|
case 0:
|
|
rasterizer_desc.CullMode = D3D11_CULL_NONE;
|
|
break;
|
|
case 1:
|
|
rasterizer_desc.CullMode = D3D11_CULL_FRONT;
|
|
break;
|
|
case 2:
|
|
rasterizer_desc.CullMode = D3D11_CULL_BACK;
|
|
break;
|
|
}
|
|
if (state_overrides & STATE_OVERRIDE_DISABLE_CULLING) {
|
|
rasterizer_desc.CullMode = D3D11_CULL_NONE;
|
|
}
|
|
rasterizer_desc.FrontCounterClockwise = (mode_control & 0x4) == 0;
|
|
rasterizer_desc.DepthBias = 0;
|
|
rasterizer_desc.DepthBiasClamp = 0;
|
|
rasterizer_desc.SlopeScaledDepthBias = 0;
|
|
rasterizer_desc.DepthClipEnable = false; // ?
|
|
rasterizer_desc.ScissorEnable = false;
|
|
rasterizer_desc.MultisampleEnable = false;
|
|
rasterizer_desc.AntialiasedLineEnable = false;
|
|
ID3D11RasterizerState* rasterizer_state = 0;
|
|
device_->CreateRasterizerState(&rasterizer_desc, &rasterizer_state);
|
|
context_->RSSetState(rasterizer_state);
|
|
XESAFERELEASE(rasterizer_state);
|
|
|
|
// Viewport.
|
|
// If we have resized the window we will want to change this.
|
|
uint32_t window_offset = rf.values[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32;
|
|
// signed?
|
|
uint32_t window_offset_x = window_offset & 0x7FFF;
|
|
uint32_t window_offset_y = (window_offset >> 16) & 0x7FFF;
|
|
|
|
// ?
|
|
// TODO(benvanik): figure out how to emulate viewports in D3D11. Could use
|
|
// viewport above to scale, though that doesn't support negatives/etc.
|
|
uint32_t vte_control = rf.values[XE_GPU_REG_PA_CL_VTE_CNTL].u32;
|
|
bool vport_xscale_enable = (vte_control & (1 << 0)) > 0;
|
|
float vport_xscale = rf.values[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32; // 640
|
|
bool vport_xoffset_enable = (vte_control & (1 << 1)) > 0;
|
|
float vport_xoffset = rf.values[XE_GPU_REG_PA_CL_VPORT_XOFFSET].f32; // 640
|
|
bool vport_yscale_enable = (vte_control & (1 << 2)) > 0;
|
|
float vport_yscale = rf.values[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32; // -360
|
|
bool vport_yoffset_enable = (vte_control & (1 << 3)) > 0;
|
|
float vport_yoffset = rf.values[XE_GPU_REG_PA_CL_VPORT_YOFFSET].f32; // 360
|
|
bool vport_zscale_enable = (vte_control & (1 << 4)) > 0;
|
|
float vport_zscale = rf.values[XE_GPU_REG_PA_CL_VPORT_ZSCALE].f32; // 1
|
|
bool vport_zoffset_enable = (vte_control & (1 << 5)) > 0;
|
|
float vport_zoffset = rf.values[XE_GPU_REG_PA_CL_VPORT_ZOFFSET].f32; // 0
|
|
|
|
// TODO(benvanik): compute viewport values.
|
|
D3D11_VIEWPORT viewport;
|
|
if (vport_xscale_enable) {
|
|
// Viewport enabled.
|
|
viewport.MinDepth = 0.0f;
|
|
viewport.MaxDepth = 1.0f;
|
|
viewport.TopLeftX = 0;
|
|
viewport.TopLeftY = 0;
|
|
viewport.Width = 1280;
|
|
viewport.Height = 720;
|
|
} else {
|
|
// Viewport disabled. Geometry shaders will compensate for this.
|
|
viewport.MinDepth = 0.0f;
|
|
viewport.MaxDepth = 1.0f;
|
|
viewport.TopLeftX = 0;
|
|
viewport.TopLeftY = 0;
|
|
viewport.Width = 1280;
|
|
viewport.Height = 720;
|
|
}
|
|
context_->RSSetViewports(1, &viewport);
|
|
|
|
// Viewport constants from D3D11VertexShader.
|
|
//"cbuffer vs_consts {\n"
|
|
//" float4 window;\n" // x,y,w,h
|
|
//" float4 viewport_z_enable;\n" // min,(max - min),?,enabled
|
|
//" float4 viewport_size;\n" // x,y,w,h
|
|
//"};"
|
|
// TODO(benvanik): only when viewport changes.
|
|
D3D11_MAPPED_SUBRESOURCE res;
|
|
context_->Map(
|
|
state_.constant_buffers.vs_consts, 0,
|
|
D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
float* vsc_buffer = (float*)res.pData;
|
|
vsc_buffer[0] = (float)window_offset_x;
|
|
vsc_buffer[1] = (float)window_offset_y;
|
|
vsc_buffer[2] = (float)window_width;
|
|
vsc_buffer[3] = (float)window_height;
|
|
vsc_buffer[4] = viewport.MinDepth;
|
|
vsc_buffer[5] = viewport.MaxDepth - viewport.MinDepth;
|
|
vsc_buffer[6] = 0; // unused
|
|
vsc_buffer[7] = vport_xscale_enable ? 1.0f : 0.0f;
|
|
vsc_buffer[8] = viewport.TopLeftX;
|
|
vsc_buffer[9] = viewport.TopLeftY;
|
|
vsc_buffer[10] = viewport.Width;
|
|
vsc_buffer[11] = viewport.Height;
|
|
context_->Unmap(state_.constant_buffers.vs_consts, 0);
|
|
|
|
// Scissoring.
|
|
// TODO(benvanik): pull from scissor registers.
|
|
// ScissorEnable must be set in raster state above.
|
|
uint32_t screen_scissor_tl = rf.values[XE_GPU_REG_PA_SC_SCREEN_SCISSOR_TL].u32;
|
|
uint32_t screen_scissor_br = rf.values[XE_GPU_REG_PA_SC_SCREEN_SCISSOR_BR].u32;
|
|
if (screen_scissor_tl != 0 && screen_scissor_br != 0x20002000) {
|
|
D3D11_RECT scissor_rect;
|
|
scissor_rect.top = (screen_scissor_tl >> 16) & 0x7FFF;
|
|
scissor_rect.left = screen_scissor_tl & 0x7FFF;
|
|
scissor_rect.bottom = (screen_scissor_br >> 16) & 0x7FFF;
|
|
scissor_rect.right = screen_scissor_br & 0x7FFF;
|
|
context_->RSSetScissorRects(1, &scissor_rect);
|
|
} else {
|
|
context_->RSSetScissorRects(0, NULL);
|
|
}
|
|
|
|
static const D3D11_COMPARISON_FUNC compare_func_map[] = {
|
|
/* 0 */ D3D11_COMPARISON_NEVER,
|
|
/* 1 */ D3D11_COMPARISON_LESS,
|
|
/* 2 */ D3D11_COMPARISON_EQUAL,
|
|
/* 3 */ D3D11_COMPARISON_LESS_EQUAL,
|
|
/* 4 */ D3D11_COMPARISON_GREATER,
|
|
/* 5 */ D3D11_COMPARISON_NOT_EQUAL,
|
|
/* 6 */ D3D11_COMPARISON_GREATER_EQUAL,
|
|
/* 7 */ D3D11_COMPARISON_ALWAYS,
|
|
};
|
|
static const D3D11_STENCIL_OP stencil_op_map[] = {
|
|
/* 0 */ D3D11_STENCIL_OP_KEEP,
|
|
/* 1 */ D3D11_STENCIL_OP_ZERO,
|
|
/* 2 */ D3D11_STENCIL_OP_REPLACE,
|
|
/* 3 */ D3D11_STENCIL_OP_INCR_SAT,
|
|
/* 4 */ D3D11_STENCIL_OP_DECR_SAT,
|
|
/* 5 */ D3D11_STENCIL_OP_INVERT,
|
|
/* 6 */ D3D11_STENCIL_OP_INCR,
|
|
/* 7 */ D3D11_STENCIL_OP_DECR,
|
|
};
|
|
|
|
// Depth-stencil state.
|
|
uint32_t depth_control = rf.values[XE_GPU_REG_RB_DEPTHCONTROL].u32;
|
|
uint32_t stencil_ref_mask = rf.values[XE_GPU_REG_RB_STENCILREFMASK].u32;
|
|
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc;
|
|
xe_zero_struct(&depth_stencil_desc, sizeof(depth_stencil_desc));
|
|
// A2XX_RB_DEPTHCONTROL_BACKFACE_ENABLE
|
|
// ?
|
|
// A2XX_RB_DEPTHCONTROL_Z_ENABLE
|
|
depth_stencil_desc.DepthEnable = (depth_control & 0x00000002) != 0;
|
|
// A2XX_RB_DEPTHCONTROL_Z_WRITE_ENABLE
|
|
depth_stencil_desc.DepthWriteMask = (depth_control & 0x00000004) ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
|
|
// A2XX_RB_DEPTHCONTROL_EARLY_Z_ENABLE
|
|
// ?
|
|
// A2XX_RB_DEPTHCONTROL_ZFUNC
|
|
depth_stencil_desc.DepthFunc = compare_func_map[(depth_control & 0x00000070) >> 4];
|
|
// A2XX_RB_DEPTHCONTROL_STENCIL_ENABLE
|
|
depth_stencil_desc.StencilEnable = (depth_control & 0x00000001) != 0;
|
|
// RB_STENCILREFMASK_STENCILMASK
|
|
depth_stencil_desc.StencilReadMask = (stencil_ref_mask & 0x0000FF00) >> 8;
|
|
// RB_STENCILREFMASK_STENCILWRITEMASK
|
|
depth_stencil_desc.StencilWriteMask = (stencil_ref_mask & 0x00FF0000) >> 16;
|
|
// A2XX_RB_DEPTHCONTROL_STENCILFUNC
|
|
depth_stencil_desc.FrontFace.StencilFunc = compare_func_map[(depth_control & 0x00000700) >> 8];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILFAIL
|
|
depth_stencil_desc.FrontFace.StencilFailOp = stencil_op_map[(depth_control & 0x00003800) >> 11];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILZPASS
|
|
depth_stencil_desc.FrontFace.StencilPassOp = stencil_op_map[(depth_control & 0x0001C000) >> 14];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILZFAIL
|
|
depth_stencil_desc.FrontFace.StencilDepthFailOp = stencil_op_map[(depth_control & 0x000E0000) >> 17];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILFUNC_BF
|
|
depth_stencil_desc.BackFace.StencilFunc = compare_func_map[(depth_control & 0x00700000) >> 20];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILFAIL_BF
|
|
depth_stencil_desc.BackFace.StencilFailOp = stencil_op_map[(depth_control & 0x03800000) >> 23];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILZPASS_BF
|
|
depth_stencil_desc.BackFace.StencilPassOp = stencil_op_map[(depth_control & 0x1C000000) >> 26];
|
|
// A2XX_RB_DEPTHCONTROL_STENCILZFAIL_BF
|
|
depth_stencil_desc.BackFace.StencilDepthFailOp = stencil_op_map[(depth_control & 0xE0000000) >> 29];
|
|
// RB_STENCILREFMASK_STENCILREF
|
|
uint32_t stencil_ref = (stencil_ref_mask & 0x000000FF);
|
|
ID3D11DepthStencilState* depth_stencil_state = 0;
|
|
device_->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state);
|
|
context_->OMSetDepthStencilState(depth_stencil_state, stencil_ref);
|
|
XESAFERELEASE(depth_stencil_state);
|
|
|
|
static const D3D11_BLEND blend_map[] = {
|
|
/* 0 */ D3D11_BLEND_ZERO,
|
|
/* 1 */ D3D11_BLEND_ONE,
|
|
/* 2 */ D3D11_BLEND_ZERO, // ?
|
|
/* 3 */ D3D11_BLEND_ZERO, // ?
|
|
/* 4 */ D3D11_BLEND_SRC_COLOR,
|
|
/* 5 */ D3D11_BLEND_INV_SRC_COLOR,
|
|
/* 6 */ D3D11_BLEND_SRC_ALPHA,
|
|
/* 7 */ D3D11_BLEND_INV_SRC_ALPHA,
|
|
/* 8 */ D3D11_BLEND_DEST_COLOR,
|
|
/* 9 */ D3D11_BLEND_INV_DEST_COLOR,
|
|
/* 10 */ D3D11_BLEND_DEST_ALPHA,
|
|
/* 11 */ D3D11_BLEND_INV_DEST_ALPHA,
|
|
/* 12 */ D3D11_BLEND_BLEND_FACTOR,
|
|
/* 13 */ D3D11_BLEND_INV_BLEND_FACTOR,
|
|
/* 14 */ D3D11_BLEND_SRC1_ALPHA, // ?
|
|
/* 15 */ D3D11_BLEND_INV_SRC1_ALPHA, // ?
|
|
/* 16 */ D3D11_BLEND_SRC_ALPHA_SAT,
|
|
};
|
|
static const D3D11_BLEND_OP blend_op_map[] = {
|
|
/* 0 */ D3D11_BLEND_OP_ADD,
|
|
/* 1 */ D3D11_BLEND_OP_SUBTRACT,
|
|
/* 2 */ D3D11_BLEND_OP_MIN,
|
|
/* 3 */ D3D11_BLEND_OP_MAX,
|
|
/* 4 */ D3D11_BLEND_OP_REV_SUBTRACT,
|
|
};
|
|
|
|
// alpha testing -- ALPHAREF, ALPHAFUNC, ALPHATESTENABLE
|
|
// Not in D3D11!
|
|
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb205120(v=vs.85).aspx
|
|
uint32_t color_control = rf.values[XE_GPU_REG_RB_COLORCONTROL].u32;
|
|
|
|
// Blend state.
|
|
uint32_t color_mask = rf.values[XE_GPU_REG_RB_COLOR_MASK].u32;
|
|
uint32_t sample_mask = 0xFFFFFFFF; // ?
|
|
float blend_factor[4] = {
|
|
rf.values[XE_GPU_REG_RB_BLEND_RED].f32,
|
|
rf.values[XE_GPU_REG_RB_BLEND_GREEN].f32,
|
|
rf.values[XE_GPU_REG_RB_BLEND_BLUE].f32,
|
|
rf.values[XE_GPU_REG_RB_BLEND_ALPHA].f32,
|
|
};
|
|
uint32_t blend_control[4] = {
|
|
rf.values[XE_GPU_REG_RB_BLENDCONTROL_0].u32,
|
|
rf.values[XE_GPU_REG_RB_BLENDCONTROL_1].u32,
|
|
rf.values[XE_GPU_REG_RB_BLENDCONTROL_2].u32,
|
|
rf.values[XE_GPU_REG_RB_BLENDCONTROL_3].u32,
|
|
};
|
|
D3D11_BLEND_DESC blend_desc;
|
|
xe_zero_struct(&blend_desc, sizeof(blend_desc));
|
|
//blend_desc.AlphaToCoverageEnable = false;
|
|
// ?
|
|
blend_desc.IndependentBlendEnable = true;
|
|
for (int n = 0; n < XECOUNT(blend_control); n++) {
|
|
// A2XX_RB_BLEND_CONTROL_COLOR_SRCBLEND
|
|
blend_desc.RenderTarget[n].SrcBlend = blend_map[(blend_control[n] & 0x0000001F) >> 0];
|
|
// A2XX_RB_BLEND_CONTROL_COLOR_DESTBLEND
|
|
blend_desc.RenderTarget[n].DestBlend = blend_map[(blend_control[n] & 0x00001F00) >> 8];
|
|
// A2XX_RB_BLEND_CONTROL_COLOR_COMB_FCN
|
|
blend_desc.RenderTarget[n].BlendOp = blend_op_map[(blend_control[n] & 0x000000E0) >> 5];
|
|
// A2XX_RB_BLEND_CONTROL_ALPHA_SRCBLEND
|
|
blend_desc.RenderTarget[n].SrcBlendAlpha = blend_map[(blend_control[n] & 0x001F0000) >> 16];
|
|
// A2XX_RB_BLEND_CONTROL_ALPHA_DESTBLEND
|
|
blend_desc.RenderTarget[n].DestBlendAlpha = blend_map[(blend_control[n] & 0x1F000000) >> 24];
|
|
// A2XX_RB_BLEND_CONTROL_ALPHA_COMB_FCN
|
|
blend_desc.RenderTarget[n].BlendOpAlpha = blend_op_map[(blend_control[n] & 0x00E00000) >> 21];
|
|
// A2XX_RB_COLOR_MASK_WRITE_*
|
|
blend_desc.RenderTarget[n].RenderTargetWriteMask = (color_mask >> (n * 4)) & 0xF;
|
|
// A2XX_RB_COLORCONTROL_BLEND_DISABLE ?? Can't find this!
|
|
// Just guess based on actions.
|
|
blend_desc.RenderTarget[n].BlendEnable = !(
|
|
(blend_desc.RenderTarget[n].SrcBlend == D3D11_BLEND_ONE) &&
|
|
(blend_desc.RenderTarget[n].DestBlend == D3D11_BLEND_ZERO) &&
|
|
(blend_desc.RenderTarget[n].BlendOp == D3D11_BLEND_OP_ADD) &&
|
|
(blend_desc.RenderTarget[n].SrcBlendAlpha == D3D11_BLEND_ONE) &&
|
|
(blend_desc.RenderTarget[n].DestBlendAlpha == D3D11_BLEND_ZERO) &&
|
|
(blend_desc.RenderTarget[n].BlendOpAlpha == D3D11_BLEND_OP_ADD));
|
|
}
|
|
ID3D11BlendState* blend_state = 0;
|
|
device_->CreateBlendState(&blend_desc, &blend_state);
|
|
context_->OMSetBlendState(blend_state, blend_factor, sample_mask);
|
|
XESAFERELEASE(blend_state);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::UpdateConstantBuffers() {
|
|
RegisterFile& rf = register_file_;
|
|
|
|
D3D11_MAPPED_SUBRESOURCE res;
|
|
context_->Map(
|
|
state_.constant_buffers.float_constants, 0,
|
|
D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
memcpy(res.pData,
|
|
&rf.values[XE_GPU_REG_SHADER_CONSTANT_000_X],
|
|
(512 * 4) * sizeof(float));
|
|
context_->Unmap(state_.constant_buffers.float_constants, 0);
|
|
|
|
context_->Map(
|
|
state_.constant_buffers.loop_constants, 0,
|
|
D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
memcpy(res.pData,
|
|
&rf.values[XE_GPU_REG_SHADER_CONSTANT_LOOP_00],
|
|
(32) * sizeof(int));
|
|
context_->Unmap(state_.constant_buffers.loop_constants, 0);
|
|
|
|
context_->Map(
|
|
state_.constant_buffers.bool_constants, 0,
|
|
D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
memcpy(res.pData,
|
|
&rf.values[XE_GPU_REG_SHADER_CONSTANT_BOOL_000_031],
|
|
(8) * sizeof(int));
|
|
context_->Unmap(state_.constant_buffers.bool_constants, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::BindShaders() {
|
|
RegisterFile& rf = register_file_;
|
|
xe_gpu_program_cntl_t program_cntl;
|
|
program_cntl.dword_0 = rf.values[XE_GPU_REG_SQ_PROGRAM_CNTL].u32;
|
|
|
|
// Vertex shader setup.
|
|
D3D11VertexShader* vs = state_.vertex_shader;
|
|
if (vs) {
|
|
if (!vs->is_prepared()) {
|
|
// Prepare for use.
|
|
if (vs->Prepare(&program_cntl)) {
|
|
XELOGGPU("D3D11: failed to prepare vertex shader");
|
|
state_.vertex_shader = NULL;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Bind.
|
|
context_->VSSetShader(vs->handle(), NULL, 0);
|
|
|
|
// Set constant buffers.
|
|
ID3D11Buffer* vs_constant_buffers[] = {
|
|
state_.constant_buffers.float_constants,
|
|
state_.constant_buffers.bool_constants,
|
|
state_.constant_buffers.loop_constants,
|
|
state_.constant_buffers.vs_consts,
|
|
};
|
|
context_->VSSetConstantBuffers(
|
|
0, XECOUNT(vs_constant_buffers), vs_constant_buffers);
|
|
|
|
// Setup input layout (as encoded in vertex shader).
|
|
context_->IASetInputLayout(vs->input_layout());
|
|
|
|
//context_->VSSetSamplers
|
|
//context_->VSSetShaderResources
|
|
} else {
|
|
context_->VSSetShader(NULL, NULL, 0);
|
|
context_->IASetInputLayout(NULL);
|
|
return 1;
|
|
}
|
|
|
|
// Pixel shader setup.
|
|
D3D11PixelShader* ps = state_.pixel_shader;
|
|
if (ps) {
|
|
if (!ps->is_prepared()) {
|
|
// Prepare for use.
|
|
if (ps->Prepare(&program_cntl, vs)) {
|
|
XELOGGPU("D3D11: failed to prepare pixel shader");
|
|
state_.pixel_shader = NULL;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Bind.
|
|
context_->PSSetShader(ps->handle(), NULL, 0);
|
|
|
|
// Set constant buffers.
|
|
ID3D11Buffer* vs_constant_buffers[] = {
|
|
state_.constant_buffers.float_constants,
|
|
state_.constant_buffers.bool_constants,
|
|
state_.constant_buffers.loop_constants,
|
|
};
|
|
context_->PSSetConstantBuffers(
|
|
0, XECOUNT(vs_constant_buffers), vs_constant_buffers);
|
|
|
|
// TODO(benvanik): set samplers for all inputs.
|
|
D3D11_SAMPLER_DESC sampler_desc;
|
|
xe_zero_struct(&sampler_desc, sizeof(sampler_desc));
|
|
//sampler_desc.Filter = ?
|
|
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.MipLODBias = 0;
|
|
sampler_desc.MaxAnisotropy = 1;
|
|
sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
|
//sampler_desc.BorderColor = ...;
|
|
sampler_desc.MinLOD = 0;
|
|
sampler_desc.MaxLOD = 0;
|
|
ID3D11SamplerState* sampler_state = NULL;
|
|
device_->CreateSamplerState(&sampler_desc, &sampler_state);
|
|
ID3D11SamplerState* sampler_states[] = { sampler_state };
|
|
context_->PSSetSamplers(0, XECOUNT(sampler_states), sampler_states);
|
|
sampler_state->Release();
|
|
|
|
//context_->PSSetShaderResources
|
|
} else {
|
|
context_->PSSetShader(NULL, NULL, 0);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::PrepareFetchers() {
|
|
// Input assembly.
|
|
XEASSERTNOTNULL(state_.vertex_shader);
|
|
auto vtx_inputs = state_.vertex_shader->GetVertexBufferInputs();
|
|
for (size_t n = 0; n < vtx_inputs->count; n++) {
|
|
auto input = vtx_inputs->descs[n];
|
|
if (PrepareVertexBuffer(input)) {
|
|
XELOGE("D3D11: unable to prepare vertex buffer");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// All texture inputs.
|
|
if (PrepareTextureFetchers()) {
|
|
XELOGE("D3D11: unable to prepare texture fetchers");
|
|
return 1;
|
|
}
|
|
|
|
// Vertex texture samplers.
|
|
auto tex_inputs = state_.vertex_shader->GetTextureBufferInputs();
|
|
for (size_t n = 0; n < tex_inputs->count; n++) {
|
|
auto input = tex_inputs->descs[n];
|
|
if (PrepareTextureSampler(XE_GPU_SHADER_TYPE_VERTEX, input)) {
|
|
XELOGE("D3D11: unable to prepare texture buffer");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Pixel shader texture sampler.
|
|
XEASSERTNOTNULL(state_.pixel_shader);
|
|
tex_inputs = state_.pixel_shader->GetTextureBufferInputs();
|
|
for (size_t n = 0; n < tex_inputs->count; n++) {
|
|
auto input = tex_inputs->descs[n];
|
|
if (PrepareTextureSampler(XE_GPU_SHADER_TYPE_PIXEL, input)) {
|
|
XELOGE("D3D11: unable to prepare texture buffer");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::PrepareVertexBuffer(Shader::vtx_buffer_desc_t& desc) {
|
|
RegisterFile& rf = register_file_;
|
|
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + (desc.fetch_slot / 3) * 6;
|
|
xe_gpu_fetch_group_t* group = (xe_gpu_fetch_group_t*)&rf.values[r];
|
|
xe_gpu_vertex_fetch_t* fetch = NULL;
|
|
switch (desc.fetch_slot % 3) {
|
|
case 0:
|
|
fetch = &group->vertex_fetch_0;
|
|
break;
|
|
case 1:
|
|
fetch = &group->vertex_fetch_1;
|
|
break;
|
|
case 2:
|
|
fetch = &group->vertex_fetch_2;
|
|
break;
|
|
}
|
|
XEASSERTNOTNULL(fetch);
|
|
// If this assert doesn't hold, maybe we just abort?
|
|
XEASSERT(fetch->type == 0x3);
|
|
XEASSERTNOTZERO(fetch->size);
|
|
|
|
ID3D11Buffer* buffer = 0;
|
|
D3D11_BUFFER_DESC buffer_desc;
|
|
xe_zero_struct(&buffer_desc, sizeof(buffer_desc));
|
|
buffer_desc.ByteWidth = fetch->size * 4;
|
|
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
|
|
buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
|
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
HRESULT hr = device_->CreateBuffer(&buffer_desc, NULL, &buffer);
|
|
if (FAILED(hr)) {
|
|
XELOGE("D3D11: unable to create vertex fetch buffer");
|
|
return 1;
|
|
}
|
|
D3D11_MAPPED_SUBRESOURCE res;
|
|
hr = context_->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
if (FAILED(hr)) {
|
|
XELOGE("D3D11: unable to map vertex fetch buffer");
|
|
XESAFERELEASE(buffer);
|
|
return 1;
|
|
}
|
|
uint32_t address = (fetch->address << 2) + address_translation_;
|
|
uint8_t* src = (uint8_t*)memory_->Translate(address);
|
|
uint8_t* dest = (uint8_t*)res.pData;
|
|
// TODO(benvanik): rewrite to be faster/special case common/etc
|
|
for (size_t n = 0; n < desc.element_count; n++) {
|
|
auto& el = desc.elements[n];
|
|
uint32_t stride = desc.stride_words;
|
|
uint32_t count = fetch->size / stride;
|
|
uint32_t* src_ptr = (uint32_t*)(src + el.offset_words * 4);
|
|
uint32_t* dest_ptr = (uint32_t*)(dest + el.offset_words * 4);
|
|
uint32_t o = 0;
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
for (uint32_t j = 0; j < el.size_words; j++) {
|
|
dest_ptr[o + j] = XESWAP32(src_ptr[o + j]);
|
|
}
|
|
o += stride;
|
|
}
|
|
}
|
|
context_->Unmap(buffer, 0);
|
|
|
|
D3D11VertexShader* vs = state_.vertex_shader;
|
|
if (!vs) {
|
|
return 1;
|
|
}
|
|
// TODO(benvanik): always dword aligned?
|
|
uint32_t stride = desc.stride_words * 4;
|
|
uint32_t offset = 0;
|
|
int vb_slot = desc.input_index;
|
|
context_->IASetVertexBuffers(vb_slot, 1, &buffer, &stride, &offset);
|
|
|
|
buffer->Release();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::PrepareTextureFetchers() {
|
|
RegisterFile& rf = register_file_;
|
|
|
|
for (int n = 0; n < XECOUNT(state_.texture_fetchers); n++) {
|
|
auto& fetcher = state_.texture_fetchers[n];
|
|
|
|
// TODO(benvanik): caching.
|
|
fetcher.enabled = false;
|
|
XESAFERELEASE(fetcher.view);
|
|
fetcher.view = NULL;
|
|
|
|
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + n * 6;
|
|
xe_gpu_fetch_group_t* group = (xe_gpu_fetch_group_t*)&rf.values[r];
|
|
auto& fetch = group->texture_fetch;
|
|
if (fetch.type != 0x2) {
|
|
continue;
|
|
}
|
|
|
|
fetcher.info = GetTextureInfo(fetch);
|
|
if (fetcher.info.format == DXGI_FORMAT_UNKNOWN) {
|
|
XELOGW("D3D11: unknown texture format %d", fetch.format);
|
|
continue;
|
|
}
|
|
|
|
D3D11_SHADER_RESOURCE_VIEW_DESC texture_view_desc;
|
|
xe_zero_struct(&texture_view_desc, sizeof(texture_view_desc));
|
|
// TODO(benvanik): this may need to be typed on the fetch instruction (float/int/etc?)
|
|
texture_view_desc.Format = fetcher.info.format;
|
|
|
|
ID3D11Resource* texture = NULL;
|
|
D3D_SRV_DIMENSION dimension = D3D11_SRV_DIMENSION_UNKNOWN;
|
|
switch (fetch.dimension) {
|
|
case DIMENSION_1D:
|
|
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
|
|
texture_view_desc.Texture1D.MipLevels = 1;
|
|
texture_view_desc.Texture1D.MostDetailedMip = 0;
|
|
if (FetchTexture1D(fetch, fetcher.info, &texture)) {
|
|
XELOGE("D3D11: failed to fetch Texture1D");
|
|
return 1;
|
|
}
|
|
break;
|
|
case DIMENSION_2D:
|
|
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
|
texture_view_desc.Texture2D.MipLevels = 1;
|
|
texture_view_desc.Texture2D.MostDetailedMip = 0;
|
|
if (FetchTexture2D(fetch, fetcher.info, &texture)) {
|
|
XELOGE("D3D11: failed to fetch Texture2D");
|
|
return 1;
|
|
}
|
|
break;
|
|
case DIMENSION_3D:
|
|
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
|
|
texture_view_desc.Texture3D.MipLevels = 1;
|
|
texture_view_desc.Texture3D.MostDetailedMip = 0;
|
|
if (FetchTexture3D(fetch, fetcher.info, &texture)) {
|
|
XELOGE("D3D11: failed to fetch Texture3D");
|
|
return 1;
|
|
}
|
|
break;
|
|
case DIMENSION_CUBE:
|
|
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
|
|
texture_view_desc.TextureCube.MipLevels = 1;
|
|
texture_view_desc.TextureCube.MostDetailedMip = 0;
|
|
if (FetchTextureCube(fetch, fetcher.info, &texture)) {
|
|
XELOGE("D3D11: failed to fetch TextureCube");
|
|
return 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
XEASSERTNOTNULL(texture);
|
|
|
|
ID3D11ShaderResourceView* texture_view = NULL;
|
|
HRESULT hr = device_->CreateShaderResourceView(
|
|
texture, &texture_view_desc, &texture_view);
|
|
if (FAILED(hr)) {
|
|
XELOGE("D3D11: unable to create texture resource view");
|
|
texture->Release();
|
|
return 1;
|
|
}
|
|
texture->Release();
|
|
|
|
fetcher.enabled = true;
|
|
fetcher.view = texture_view;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
D3D11GraphicsDriver::TextureInfo D3D11GraphicsDriver::GetTextureInfo(
|
|
xe_gpu_texture_fetch_t& fetch) {
|
|
// a2xx_sq_surfaceformat
|
|
TextureInfo info;
|
|
info.format = DXGI_FORMAT_UNKNOWN;
|
|
info.block_size = 0;
|
|
info.pitch = 0;
|
|
info.needs_power_of_two = false;
|
|
switch (fetch.format) {
|
|
case FMT_8:
|
|
info.format = DXGI_FORMAT_R8_UNORM;
|
|
info.block_size = 1;
|
|
info.pitch = 1;
|
|
break;
|
|
case FMT_8_8_8_8:
|
|
info.format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
|
info.block_size = 1;
|
|
info.pitch = 4;
|
|
break;
|
|
case FMT_4_4_4_4:
|
|
info.format = DXGI_FORMAT_B4G4R4A4_UNORM;
|
|
info.block_size = 1;
|
|
info.pitch = 2;
|
|
break;
|
|
case FMT_16_16_16_16_FLOAT:
|
|
info.format = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
|
info.block_size = 1;
|
|
info.pitch = 8;
|
|
break;
|
|
case FMT_32_FLOAT:
|
|
info.format = DXGI_FORMAT_R32_FLOAT;
|
|
info.block_size = 1;
|
|
info.pitch = 4;
|
|
break;
|
|
case FMT_DXT1:
|
|
info.format = DXGI_FORMAT_BC1_UNORM;
|
|
info.block_size = 4;
|
|
info.pitch = 8;
|
|
info.needs_power_of_two = true;
|
|
break;
|
|
case FMT_DXT2_3:
|
|
case FMT_DXT4_5:
|
|
info.format = (fetch.format == FMT_DXT4_5 ? DXGI_FORMAT_BC3_UNORM : DXGI_FORMAT_BC2_UNORM);
|
|
info.block_size = 4;
|
|
info.pitch = 16;
|
|
info.needs_power_of_two = true;
|
|
break;
|
|
case FMT_1_REVERSE:
|
|
case FMT_1:
|
|
case FMT_1_5_5_5:
|
|
case FMT_5_6_5:
|
|
case FMT_6_5_5:
|
|
case FMT_2_10_10_10:
|
|
case FMT_8_A:
|
|
case FMT_8_B:
|
|
case FMT_8_8:
|
|
case FMT_Cr_Y1_Cb_Y0:
|
|
case FMT_Y1_Cr_Y0_Cb:
|
|
case FMT_5_5_5_1:
|
|
case FMT_8_8_8_8_A:
|
|
case FMT_10_11_11:
|
|
case FMT_11_11_10:
|
|
case FMT_24_8:
|
|
case FMT_24_8_FLOAT:
|
|
case FMT_16:
|
|
case FMT_16_16:
|
|
case FMT_16_16_16_16:
|
|
case FMT_16_EXPAND:
|
|
case FMT_16_16_EXPAND:
|
|
case FMT_16_16_16_16_EXPAND:
|
|
case FMT_16_FLOAT:
|
|
case FMT_16_16_FLOAT:
|
|
case FMT_32:
|
|
case FMT_32_32:
|
|
case FMT_32_32_32_32:
|
|
case FMT_32_32_FLOAT:
|
|
case FMT_32_32_32_32_FLOAT:
|
|
case FMT_32_AS_8:
|
|
case FMT_32_AS_8_8:
|
|
case FMT_16_MPEG:
|
|
case FMT_16_16_MPEG:
|
|
case FMT_8_INTERLACED:
|
|
case FMT_32_AS_8_INTERLACED:
|
|
case FMT_32_AS_8_8_INTERLACED:
|
|
case FMT_16_INTERLACED:
|
|
case FMT_16_MPEG_INTERLACED:
|
|
case FMT_16_16_MPEG_INTERLACED:
|
|
case FMT_DXN:
|
|
case FMT_8_8_8_8_AS_16_16_16_16:
|
|
case FMT_DXT1_AS_16_16_16_16:
|
|
case FMT_DXT2_3_AS_16_16_16_16:
|
|
case FMT_DXT4_5_AS_16_16_16_16:
|
|
case FMT_2_10_10_10_AS_16_16_16_16:
|
|
case FMT_10_11_11_AS_16_16_16_16:
|
|
case FMT_11_11_10_AS_16_16_16_16:
|
|
case FMT_32_32_32_FLOAT:
|
|
case FMT_DXT3A:
|
|
case FMT_DXT5A:
|
|
case FMT_CTX1:
|
|
case FMT_DXT3A_AS_1_1_1_1:
|
|
info.format = DXGI_FORMAT_UNKNOWN;
|
|
break;
|
|
}
|
|
return info;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::FetchTexture1D(
|
|
xe_gpu_texture_fetch_t& fetch,
|
|
TextureInfo& info,
|
|
ID3D11Resource** out_texture) {
|
|
uint32_t address = (fetch.address << 12) + address_translation_;
|
|
|
|
uint32_t width = 1 + fetch.size_1d.width;
|
|
|
|
D3D11_TEXTURE1D_DESC texture_desc;
|
|
xe_zero_struct(&texture_desc, sizeof(texture_desc));
|
|
texture_desc.Width = width;
|
|
texture_desc.MipLevels = 1;
|
|
texture_desc.ArraySize = 1;
|
|
texture_desc.Format = info.format;
|
|
texture_desc.Usage = D3D11_USAGE_DYNAMIC;
|
|
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
texture_desc.MiscFlags = 0; // D3D11_RESOURCE_MISC_GENERATE_MIPS?
|
|
HRESULT hr = device_->CreateTexture1D(
|
|
&texture_desc, NULL, (ID3D11Texture1D**)out_texture);
|
|
if (FAILED(hr)) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::FetchTexture2D(
|
|
xe_gpu_texture_fetch_t& fetch,
|
|
TextureInfo& info,
|
|
ID3D11Resource** out_texture) {
|
|
uint32_t address = (fetch.address << 12) + address_translation_;
|
|
|
|
uint32_t width = 1 + fetch.size_2d.width;
|
|
uint32_t height = 1 + fetch.size_2d.height;
|
|
uint32_t padded_width = info.needs_power_of_two == false ? width : MAX(256, XENEXTPOW2(width));
|
|
uint32_t padded_height = info.needs_power_of_two == false ? height : MAX(256, XENEXTPOW2(height));
|
|
|
|
D3D11_TEXTURE2D_DESC texture_desc;
|
|
xe_zero_struct(&texture_desc, sizeof(texture_desc));
|
|
texture_desc.Width = padded_width;
|
|
texture_desc.Height = padded_height;
|
|
texture_desc.MipLevels = 1;
|
|
texture_desc.ArraySize = 1;
|
|
texture_desc.Format = info.format;
|
|
texture_desc.SampleDesc.Count = 1;
|
|
texture_desc.SampleDesc.Quality = 0;
|
|
texture_desc.Usage = D3D11_USAGE_DYNAMIC;
|
|
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
|
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
texture_desc.MiscFlags = 0; // D3D11_RESOURCE_MISC_GENERATE_MIPS?
|
|
HRESULT hr = device_->CreateTexture2D(
|
|
&texture_desc, NULL, (ID3D11Texture2D**)out_texture);
|
|
if (FAILED(hr)) {
|
|
return 1;
|
|
}
|
|
|
|
// TODO(benvanik): all mip levels.
|
|
D3D11_MAPPED_SUBRESOURCE res;
|
|
hr = context_->Map(*out_texture, 0,
|
|
D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
if (FAILED(hr)) {
|
|
XELOGE("D3D11: failed to map texture");
|
|
return 1;
|
|
}
|
|
const uint8_t* src = memory_->Translate(address);
|
|
uint8_t* dest = (uint8_t*)res.pData;
|
|
|
|
memset(dest, 0, res.RowPitch * (padded_height / info.block_size)); // TODO(gibbed): remove me later
|
|
auto row_pitch = (width / info.block_size) * info.pitch;
|
|
auto padded_row_pitch = (padded_width / info.block_size) * info.pitch;
|
|
for (size_t y = 0; y < height / info.block_size; y++) {
|
|
for (size_t x = 0; x < row_pitch; x += 4) {
|
|
*(uint32_t*)(dest + x) = GpuSwap(XESWAP32BE(*(uint32_t*)(src + x)), (XE_GPU_ENDIAN)fetch.endianness);
|
|
}
|
|
src += padded_row_pitch;
|
|
dest += res.RowPitch;
|
|
}
|
|
|
|
context_->Unmap(*out_texture, 0);
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::FetchTexture3D(
|
|
xe_gpu_texture_fetch_t& fetch,
|
|
TextureInfo& info,
|
|
ID3D11Resource** out_texture) {
|
|
XELOGE("D3D11: FetchTexture2D not yet implemented");
|
|
XEASSERTALWAYS();
|
|
return 1;
|
|
//D3D11_TEXTURE3D_DESC texture_desc;
|
|
//xe_zero_struct(&texture_desc, sizeof(texture_desc));
|
|
//texture_desc.Width;
|
|
//texture_desc.Height;
|
|
//texture_desc.Depth;
|
|
//texture_desc.MipLevels;
|
|
//texture_desc.Format;
|
|
//texture_desc.Usage;
|
|
//texture_desc.BindFlags;
|
|
//texture_desc.CPUAccessFlags;
|
|
//texture_desc.MiscFlags;
|
|
//hr = device_->CreateTexture3D(
|
|
// &texture_desc, &initial_data, (ID3D11Texture3D**)&texture);
|
|
}
|
|
|
|
int D3D11GraphicsDriver::FetchTextureCube(
|
|
xe_gpu_texture_fetch_t& fetch,
|
|
TextureInfo& info,
|
|
ID3D11Resource** out_texture) {
|
|
XELOGE("D3D11: FetchTextureCube not yet implemented");
|
|
XEASSERTALWAYS();
|
|
return 1;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::PrepareTextureSampler(
|
|
xenos::XE_GPU_SHADER_TYPE shader_type, Shader::tex_buffer_desc_t& desc) {
|
|
|
|
auto& fetcher = state_.texture_fetchers[desc.fetch_slot];
|
|
auto& info = fetcher.info;
|
|
if (!fetcher.enabled ||
|
|
info.format == DXGI_FORMAT_UNKNOWN) {
|
|
XELOGW("D3D11: ignoring texture fetch: disabled or an unknown format");
|
|
if (shader_type == XE_GPU_SHADER_TYPE_VERTEX) {
|
|
context_->VSSetShaderResources(desc.input_index,
|
|
1, &invalid_texture_view_);
|
|
context_->VSSetSamplers(desc.input_index,
|
|
1, &invalid_texture_sampler_state_);
|
|
} else {
|
|
context_->PSSetShaderResources(desc.input_index,
|
|
1, &invalid_texture_view_);
|
|
context_->PSSetSamplers(desc.input_index,
|
|
1, &invalid_texture_sampler_state_);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
if (shader_type == XE_GPU_SHADER_TYPE_VERTEX) {
|
|
context_->VSSetShaderResources(desc.input_index, 1, &fetcher.view);
|
|
} else {
|
|
context_->PSSetShaderResources(desc.input_index, 1, &fetcher.view);
|
|
}
|
|
|
|
D3D11_SAMPLER_DESC sampler_desc;
|
|
xe_zero_struct(&sampler_desc, sizeof(sampler_desc));
|
|
sampler_desc.Filter;
|
|
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
|
sampler_desc.MipLODBias;
|
|
sampler_desc.MaxAnisotropy = 1;
|
|
sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
|
|
sampler_desc.BorderColor[0];
|
|
sampler_desc.BorderColor[1];
|
|
sampler_desc.BorderColor[2];
|
|
sampler_desc.BorderColor[3];
|
|
sampler_desc.MinLOD;
|
|
sampler_desc.MaxLOD;
|
|
ID3D11SamplerState* sampler_state = NULL;
|
|
hr = device_->CreateSamplerState(&sampler_desc, &sampler_state);
|
|
if (FAILED(hr)) {
|
|
XELOGE("D3D11: unable to create sampler state");
|
|
return 1;
|
|
}
|
|
if (shader_type == XE_GPU_SHADER_TYPE_VERTEX) {
|
|
context_->VSSetSamplers(desc.input_index, 1, &sampler_state);
|
|
} else {
|
|
context_->PSSetSamplers(desc.input_index, 1, &sampler_state);
|
|
}
|
|
sampler_state->Release();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::PrepareIndexBuffer(
|
|
bool index_32bit, uint32_t index_count,
|
|
uint32_t index_base, uint32_t index_size, uint32_t endianness) {
|
|
RegisterFile& rf = register_file_;
|
|
|
|
uint32_t address = index_base + address_translation_;
|
|
|
|
// All that's done so far:
|
|
XEASSERT(endianness == 0x2);
|
|
|
|
ID3D11Buffer* buffer = 0;
|
|
D3D11_BUFFER_DESC buffer_desc;
|
|
xe_zero_struct(&buffer_desc, sizeof(buffer_desc));
|
|
buffer_desc.ByteWidth = index_size;
|
|
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
|
|
buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
|
|
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
|
|
device_->CreateBuffer(&buffer_desc, NULL, &buffer);
|
|
D3D11_MAPPED_SUBRESOURCE res;
|
|
context_->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
|
|
if (index_32bit) {
|
|
uint32_t* src = (uint32_t*)memory_->Translate(address);
|
|
uint32_t* dest = (uint32_t*)res.pData;
|
|
for (uint32_t n = 0; n < index_count; n++) {
|
|
uint32_t d = { XESWAP32(src[n]) };
|
|
//XELOGGPU("i%.4d %0.8X", n, d);
|
|
dest[n] = d;
|
|
}
|
|
} else {
|
|
uint16_t* src = (uint16_t*)memory_->Translate(address);
|
|
uint16_t* dest = (uint16_t*)res.pData;
|
|
for (uint32_t n = 0; n < index_count; n++) {
|
|
uint16_t d = XESWAP16(src[n]);
|
|
//XELOGGPU("i%.4d, %.4X", n, d);
|
|
dest[n] = d;
|
|
}
|
|
}
|
|
context_->Unmap(buffer, 0);
|
|
|
|
DXGI_FORMAT format;
|
|
format = index_32bit ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT;
|
|
context_->IASetIndexBuffer(buffer, format, 0);
|
|
|
|
buffer->Release();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int D3D11GraphicsDriver::Resolve() {
|
|
// No clue how this is supposed to work yet.
|
|
ID3D11Texture2D* back_buffer = 0;
|
|
swap_chain_->GetBuffer(0, __uuidof(ID3D11Texture2D),
|
|
(LPVOID*)&back_buffer);
|
|
D3D11_TEXTURE2D_DESC desc;
|
|
back_buffer->GetDesc(&desc);
|
|
if (desc.Width == render_targets_.width &&
|
|
desc.Height == render_targets_.height) {
|
|
// Same size/format, so copy quickly.
|
|
context_->CopyResource(back_buffer, render_targets_.color_buffers[0].buffer);
|
|
} else {
|
|
// TODO(benvanik): scale size using a quad draw.
|
|
}
|
|
XESAFERELEASE(back_buffer);
|
|
|
|
// TODO(benvanik): remove!
|
|
float color[4] = { 0.5f, 0.5f, 0.0f, 1.0f };
|
|
context_->ClearRenderTargetView(
|
|
render_targets_.color_buffers[0].color_view_8888, color);
|
|
// TODO(benvanik): take clear values from register
|
|
context_->ClearDepthStencilView(
|
|
render_targets_.depth_view_d28s8, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0);
|
|
|
|
return 0;
|
|
}
|