Removing D3D.

This commit is contained in:
Ben Vanik 2014-12-21 01:21:39 -08:00
parent bbb7de6bff
commit 42e6a44624
26 changed files with 0 additions and 5740 deletions

View File

@ -1,155 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_buffer_resource.h>
#include <algorithm>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_resource_cache.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
D3D11IndexBufferResource::D3D11IndexBufferResource(
D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info)
: IndexBufferResource(memory_range, info),
resource_cache_(resource_cache),
handle_(nullptr) {
}
D3D11IndexBufferResource::~D3D11IndexBufferResource() {
SafeRelease(handle_);
}
int D3D11IndexBufferResource::CreateHandle() {
D3D11_BUFFER_DESC buffer_desc;
memset(&buffer_desc, 0, sizeof(buffer_desc));
buffer_desc.ByteWidth = static_cast<UINT>(memory_range_.length);
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
HRESULT hr = resource_cache_->device()->CreateBuffer(
&buffer_desc, nullptr, &handle_);
if (FAILED(hr)) {
XELOGW("D3D11: failed to create index buffer");
return 1;
}
return 0;
}
int D3D11IndexBufferResource::InvalidateRegion(
const MemoryRange& memory_range) {
SCOPE_profile_cpu_f("gpu");
// All that's done so far:
assert_true(info_.endianness == XE_GPU_ENDIAN_8IN16 ||
info_.endianness == XE_GPU_ENDIAN_8IN32);
D3D11_MAPPED_SUBRESOURCE res;
HRESULT hr = resource_cache_->context()->Map(
handle_, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
if (FAILED(hr)) {
XELOGE("D3D11: unable to map index buffer");
return 1;
}
if (info_.format == INDEX_FORMAT_32BIT) {
uint32_t index_count = memory_range_.length / 4;
const uint32_t* src = reinterpret_cast<const uint32_t*>(
memory_range_.host_base);
uint32_t* dest = reinterpret_cast<uint32_t*>(res.pData);
for (uint32_t n = 0; n < index_count; n++) {
dest[n] = poly::byte_swap(src[n]);
}
} else {
uint32_t index_count = memory_range_.length / 2;
const uint16_t* src = reinterpret_cast<const uint16_t*>(
memory_range_.host_base);
uint16_t* dest = reinterpret_cast<uint16_t*>(res.pData);
for (uint32_t n = 0; n < index_count; n++) {
dest[n] = poly::byte_swap(src[n]);
}
}
resource_cache_->context()->Unmap(handle_, 0);
return 0;
}
D3D11VertexBufferResource::D3D11VertexBufferResource(
D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info)
: VertexBufferResource(memory_range, info),
resource_cache_(resource_cache),
handle_(nullptr) {
}
D3D11VertexBufferResource::~D3D11VertexBufferResource() {
SafeRelease(handle_);
}
int D3D11VertexBufferResource::CreateHandle() {
D3D11_BUFFER_DESC buffer_desc;
memset(&buffer_desc, 0, sizeof(buffer_desc));
buffer_desc.ByteWidth = static_cast<UINT>(memory_range_.length);
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
HRESULT hr = resource_cache_->device()->CreateBuffer(
&buffer_desc, nullptr, &handle_);
if (FAILED(hr)) {
XELOGW("D3D11: failed to create vertex buffer");
return 1;
}
return 0;
}
int D3D11VertexBufferResource::InvalidateRegion(
const MemoryRange& memory_range) {
SCOPE_profile_cpu_f("gpu");
D3D11_MAPPED_SUBRESOURCE res;
HRESULT hr = resource_cache_->context()->Map(
handle_, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
if (FAILED(hr)) {
XELOGE("D3D11: unable to map vertex buffer");
return 1;
}
uint8_t* dest = reinterpret_cast<uint8_t*>(res.pData);
// TODO(benvanik): rewrite to be faster/special case common/etc
uint32_t stride = info_.stride_words;
size_t count = (memory_range_.length / 4) / stride;
if (FLAGS_max_draw_elements) {
count = std::min(FLAGS_max_draw_elements, count);
}
for (size_t n = 0; n < info_.element_count; n++) {
const auto& el = info_.elements[n];
const uint32_t* src_ptr = (const uint32_t*)(
memory_range_.host_base + 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] = poly::byte_swap(src_ptr[o + j]);
}
o += stride;
}
}
resource_cache_->context()->Unmap(handle_, 0);
return 0;
}

View File

@ -1,67 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_BUFFER_RESOURCE_H_
#define XENIA_GPU_D3D11_D3D11_BUFFER_RESOURCE_H_
#include <xenia/gpu/buffer_resource.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/xenos/xenos.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11ResourceCache;
class D3D11IndexBufferResource : public IndexBufferResource {
public:
D3D11IndexBufferResource(D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info);
~D3D11IndexBufferResource() override;
void* handle() const override { return handle_; }
protected:
int CreateHandle() override;
int InvalidateRegion(const MemoryRange& memory_range) override;
private:
D3D11ResourceCache* resource_cache_;
ID3D11Buffer* handle_;
};
class D3D11VertexBufferResource : public VertexBufferResource {
public:
D3D11VertexBufferResource(D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info);
~D3D11VertexBufferResource() override;
void* handle() const override { return handle_; }
protected:
int CreateHandle() override;
int InvalidateRegion(const MemoryRange& memory_range) override;
private:
D3D11ResourceCache* resource_cache_;
ID3D11Buffer* handle_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_BUFFER_RESOURCE_H_

View File

@ -1,286 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_geometry_shader.h>
#include <poly/math.h>
#include <xenia/core/hash.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_shader_resource.h>
#include <xenia/gpu/d3d11/d3d11_shader_translator.h>
#include <xenia/gpu/xenos/ucode.h>
#include <d3dcompiler.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
D3D11GeometryShader::D3D11GeometryShader(ID3D11Device* device)
: handle_(nullptr) {
device_ = device;
device_->AddRef();
}
D3D11GeometryShader::~D3D11GeometryShader() {
SafeRelease(handle_);
SafeRelease(device_);
}
int D3D11GeometryShader::Prepare(D3D11VertexShaderResource* vertex_shader) {
SCOPE_profile_cpu_f("gpu");
if (handle_) {
return 0;
}
// TODO(benvanik): look in file based on hash/etc.
void* byte_code = NULL;
size_t byte_code_length = 0;
// Translate and compile source.
auto output = new alloy::StringBuffer();
if (Generate(vertex_shader, output)) {
delete output;
return 1;
}
ID3D10Blob* shader_blob = Compile(output->GetString());
delete output;
if (!shader_blob) {
return 1;
}
byte_code_length = shader_blob->GetBufferSize();
byte_code = malloc(byte_code_length);
memcpy(byte_code, shader_blob->GetBufferPointer(), byte_code_length);
SafeRelease(shader_blob);
// Create shader.
HRESULT hr = device_->CreateGeometryShader(
byte_code, byte_code_length,
NULL,
&handle_);
if (FAILED(hr)) {
XELOGE("D3D11: failed to create geometry shader");
free(byte_code);
return 1;
}
return 0;
}
ID3D10Blob* D3D11GeometryShader::Compile(const char* shader_source) {
SCOPE_profile_cpu_f("gpu");
// TODO(benvanik): pick shared runtime mode defines.
D3D10_SHADER_MACRO defines[] = {
"TEST_DEFINE", "1",
0, 0,
};
uint32_t flags1 = 0;
flags1 |= D3D10_SHADER_DEBUG;
flags1 |= D3D10_SHADER_ENABLE_STRICTNESS;
uint32_t flags2 = 0;
// Create a name.
const char* base_path = "";
if (FLAGS_dump_shaders.size()) {
base_path = FLAGS_dump_shaders.c_str();
}
uint64_t hash = hash64(shader_source, strlen(shader_source)); // ?
char file_name[poly::max_path];
snprintf(file_name, poly::countof(file_name), "%s/gen_%.16llX.gs", base_path,
hash);
if (FLAGS_dump_shaders.size()) {
FILE* f = fopen(file_name, "w");
fprintf(f, shader_source);
fclose(f);
}
// Compile shader to bytecode blob.
ID3D10Blob* shader_blob = 0;
ID3D10Blob* error_blob = 0;
HRESULT hr = D3DCompile(
shader_source, strlen(shader_source),
file_name,
defines, NULL,
"main",
"gs_5_0",
flags1, flags2,
&shader_blob, &error_blob);
if (error_blob) {
char* msg = (char*)error_blob->GetBufferPointer();
XELOGE("D3D11: shader compile failed with %s", msg);
}
SafeRelease(error_blob);
if (FAILED(hr)) {
return NULL;
}
return shader_blob;
}
int D3D11GeometryShader::Generate(D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) {
output->Append(
"struct VERTEX {\n"
" float4 oPos : SV_POSITION;\n");
auto alloc_counts = vertex_shader->alloc_counts();
if (alloc_counts.params) {
// TODO(benvanik): only add used ones?
output->Append(
" float4 o[%d] : XE_O;\n",
D3D11ShaderTranslator::kMaxInterpolators);
}
if (alloc_counts.point_size) {
output->Append(
" float4 oPointSize : PSIZE;\n");
}
output->Append(
"};\n");
output->Append(
"cbuffer geo_consts {\n"
"};\n");
return 0;
}
D3D11PointSpriteGeometryShader::D3D11PointSpriteGeometryShader(
ID3D11Device* device) : D3D11GeometryShader(device) {
}
D3D11PointSpriteGeometryShader::~D3D11PointSpriteGeometryShader() {
}
int D3D11PointSpriteGeometryShader::Generate(
D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) {
SCOPE_profile_cpu_f("gpu");
if (D3D11GeometryShader::Generate(vertex_shader, output)) {
return 1;
}
auto alloc_counts = vertex_shader->alloc_counts();
// TODO(benvanik): fetch default point size from register and use that if
// the VS doesn't write oPointSize.
// TODO(benvanik): clamp to min/max.
// TODO(benvanik): figure out how to see which interpolator gets adjusted.
output->Append(
"[maxvertexcount(4)]\n"
"void main(point VERTEX input[1], inout TriangleStream<VERTEX> output) {\n"
" const float2 offsets[4] = {\n"
" float2(-1.0, 1.0),\n"
" float2( 1.0, 1.0),\n"
" float2(-1.0, -1.0),\n"
" float2( 1.0, -1.0),\n"
" };\n");
if (alloc_counts.point_size) {
// Point size specified in input.
// TODO(benvanik): pull in psize min/max.
output->Append(
" float psize = max(input[0].oPointSize.x, 1.0);\n");
} else {
// Point size from register.
// TODO(benvanik): pull in psize.
output->Append(
" float psize = 1.0;\n");
}
output->Append(
" for (uint n = 0; n < 4; n++) {\n"
" VERTEX v = input[0];\n"
" v.oPos.xy += offsets[n] * psize;\n"
" output.Append(v);\n"
" }\n"
" output.RestartStrip();\n"
"}\n");
return 0;
}
D3D11RectListGeometryShader::D3D11RectListGeometryShader(
ID3D11Device* device) : D3D11GeometryShader(device) {
}
D3D11RectListGeometryShader::~D3D11RectListGeometryShader() {
}
int D3D11RectListGeometryShader::Generate(
D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) {
SCOPE_profile_cpu_f("gpu");
if (D3D11GeometryShader::Generate(vertex_shader, output)) {
return 1;
}
auto alloc_counts = vertex_shader->alloc_counts();
output->Append(
"[maxvertexcount(4)]\n"
"void main(triangle VERTEX input[3], inout TriangleStream<VERTEX> output) {\n"
" for (uint n = 0; n < 3; n++) {\n"
" VERTEX v = input[n];\n"
" output.Append(v);\n"
" }\n"
" VERTEX v = input[2];\n"
" v.oPos += input[1].oPos - input[0].oPos;\n");
if (alloc_counts.point_size) {
output->Append(
" v.oPointSize += input[1].oPointSize - input[0].oPointSize;\n");
}
for (uint32_t n = 0; n < alloc_counts.params; n++) {
// TODO(benvanik): this may be wrong - the count is a bad metric.
output->Append(
" v.o[%d] += input[1].o[%d] - input[0].o[%d];\n",
n, n, n, n);
}
output->Append(
" output.Append(v);\n"
" output.RestartStrip();\n"
"}\n");
return 0;
}
D3D11QuadListGeometryShader::D3D11QuadListGeometryShader(
ID3D11Device* device) : D3D11GeometryShader(device) {
}
D3D11QuadListGeometryShader::~D3D11QuadListGeometryShader() {
}
int D3D11QuadListGeometryShader::Generate(
D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) {
SCOPE_profile_cpu_f("gpu");
if (D3D11GeometryShader::Generate(vertex_shader, output)) {
return 1;
}
output->Append(
"[maxvertexcount(4)]\n"
"void main(lineadj VERTEX input[4], inout TriangleStream<VERTEX> output) {\n"
" const uint order[4] = { 0, 1, 3, 2 };\n"
" for (uint n = 0; n < 4; n++) {\n"
" VERTEX v = input[order[n]];\n"
" output.Append(v);\n"
" }\n"
" output.RestartStrip();\n"
"}\n");
return 0;
}

View File

@ -1,81 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_GEOMETRY_SHADER_H_
#define XENIA_GPU_D3D11_D3D11_GEOMETRY_SHADER_H_
#include <alloy/string_buffer.h>
#include <xenia/common.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11VertexShaderResource;
class D3D11GeometryShader {
public:
virtual ~D3D11GeometryShader();
ID3D11GeometryShader* handle() const { return handle_; }
int Prepare(D3D11VertexShaderResource* vertex_shader);
protected:
D3D11GeometryShader(ID3D11Device* device);
ID3D10Blob* Compile(const char* shader_source);
virtual int Generate(D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output);
protected:
ID3D11Device* device_;
ID3D11GeometryShader* handle_;
};
class D3D11PointSpriteGeometryShader : public D3D11GeometryShader {
public:
D3D11PointSpriteGeometryShader(ID3D11Device* device);
~D3D11PointSpriteGeometryShader() override;
protected:
int Generate(D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) override;
};
class D3D11RectListGeometryShader : public D3D11GeometryShader {
public:
D3D11RectListGeometryShader(ID3D11Device* device);
~D3D11RectListGeometryShader() override;
protected:
int Generate(D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) override;
};
class D3D11QuadListGeometryShader : public D3D11GeometryShader {
public:
D3D11QuadListGeometryShader(ID3D11Device* device);
~D3D11QuadListGeometryShader() override;
protected:
int Generate(D3D11VertexShaderResource* vertex_shader,
alloy::StringBuffer* output) override;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_SHADER_H_

View File

@ -1,33 +0,0 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_GPU_PRIVATE_H_
#define XENIA_GPU_D3D11_D3D11_GPU_PRIVATE_H_
#include <d3d11.h>
#include <xenia/common.h>
#include <xenia/gpu/d3d11/d3d11_gpu.h>
namespace xe {
namespace gpu {
namespace d3d11 {
template <typename T>
void SafeRelease(T* ptr) {
if (ptr) {
ptr->Release();
}
}
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_GPU_PRIVATE_H_

View File

@ -1,40 +0,0 @@
/**
******************************************************************************
* 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_gpu.h>
#include <xenia/gpu/d3d11/d3d11_graphics_system.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
namespace {
void InitializeIfNeeded();
void CleanupOnShutdown();
void InitializeIfNeeded() {
static bool has_initialized = false;
if (has_initialized) {
return;
}
has_initialized = true;
//
atexit(CleanupOnShutdown);
}
void CleanupOnShutdown() {}
}
std::unique_ptr<GraphicsSystem> xe::gpu::d3d11::Create(Emulator* emulator) {
InitializeIfNeeded();
return std::make_unique<D3D11GraphicsSystem>(emulator);
}

View File

@ -1,32 +0,0 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_GPU_H_
#define XENIA_GPU_D3D11_D3D11_GPU_H_
#include <memory>
#include <xenia/common.h>
namespace xe {
class Emulator;
} // namespace xe
namespace xe {
namespace gpu {
class GraphicsSystem;
namespace d3d11 {
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator);
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_GPU_H_

View File

@ -1,924 +0,0 @@
/**
******************************************************************************
* 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 <poly/math.h>
#include <xenia/core/hash.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/buffer_resource.h>
#include <xenia/gpu/shader_resource.h>
#include <xenia/gpu/texture_resource.h>
#include <xenia/gpu/d3d11/d3d11_geometry_shader.h>
#include <xenia/gpu/d3d11/d3d11_shader_resource.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
#define XETRACED3D(fmt, ...) if (FLAGS_trace_ring_buffer) XELOGGPU(fmt, ##__VA_ARGS__)
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_);
resource_cache_ = new D3D11ResourceCache(memory, device_, context_);
memset(&state_, 0, sizeof(state_));
memset(&render_targets_, 0, sizeof(render_targets_));
HRESULT hr;
D3D11_BUFFER_DESC buffer_desc = {0};
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);
}
D3D11GraphicsDriver::~D3D11GraphicsDriver() {
RebuildRenderTargets(0, 0);
SafeRelease(state_.constant_buffers.float_constants);
SafeRelease(state_.constant_buffers.bool_constants);
SafeRelease(state_.constant_buffers.loop_constants);
SafeRelease(state_.constant_buffers.vs_consts);
SafeRelease(state_.constant_buffers.gs_consts);
for (auto it = rasterizer_state_cache_.begin();
it != rasterizer_state_cache_.end(); ++it) {
SafeRelease(it->second);
}
for (auto it = blend_state_cache_.begin();
it != blend_state_cache_.end(); ++it) {
SafeRelease(it->second);
}
for (auto it = depth_stencil_state_cache_.begin();
it != depth_stencil_state_cache_.end(); ++it) {
SafeRelease(it->second);
}
SafeRelease(invalid_texture_view_);
SafeRelease(invalid_texture_sampler_state_);
delete resource_cache_;
SafeRelease(context_);
SafeRelease(device_);
SafeRelease(swap_chain_);
}
int D3D11GraphicsDriver::Initialize() {
InitializeInvalidTexture();
return 0;
}
void D3D11GraphicsDriver::InitializeInvalidTexture() {
// TODO(benvanik): pattern?
D3D11_TEXTURE2D_DESC texture_desc = {0};
texture_desc.Width = 4;
texture_desc.Height = 4;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
texture_desc.Usage = D3D11_USAGE_IMMUTABLE;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0; // D3D11_RESOURCE_MISC_GENERATE_MIPS?
uint32_t texture_data[] = {
0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
};
D3D11_SUBRESOURCE_DATA initial_data;
initial_data.SysMemPitch = 4 * texture_desc.Width;
initial_data.SysMemSlicePitch = 0;
initial_data.pSysMem = texture_data;
ID3D11Texture2D* texture = NULL;
HRESULT hr = device_->CreateTexture2D(
&texture_desc, &initial_data, (ID3D11Texture2D**)&texture);
if (FAILED(hr)) {
PFATAL("D3D11: unable to create invalid texture");
return;
}
D3D11_SHADER_RESOURCE_VIEW_DESC texture_view_desc = {};
texture_view_desc.Format = texture_desc.Format;
texture_view_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
texture_view_desc.Texture2D.MipLevels = 1;
texture_view_desc.Texture2D.MostDetailedMip = 0;
hr = device_->CreateShaderResourceView(
texture, &texture_view_desc, &invalid_texture_view_);
SafeRelease(texture);
D3D11_SAMPLER_DESC 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)) {
PFATAL("D3D11: unable to create invalid sampler state");
return;
}
}
int D3D11GraphicsDriver::Draw(const DrawCommand& command) {
SCOPE_profile_cpu_f("gpu");
// Misc state.
if (UpdateState(command)) {
return 1;
}
// Build constant buffers.
if (SetupConstantBuffers(command)) {
return 1;
}
// Bind shaders.
if (SetupShaders(command)) {
return 1;
}
// Bind vertex buffers/index buffer.
if (SetupInputAssembly(command)) {
return 1;
}
// Bind texture fetchers.
if (SetupSamplers(command)) {
return 1;
}
if (command.index_buffer) {
// Have an actual index buffer.
XETRACED3D("D3D11: draw indexed %d (indicies [%d,%d] (%d))",
command.prim_type, command.start_index,
command.start_index + command.index_count, command.index_count);
context_->DrawIndexed(command.index_count, command.start_index,
command.base_vertex);
} else {
// Auto draw.
XETRACED3D("D3D11: draw indexed auto %d (indicies [%d,%d] (%d))",
command.prim_type, command.start_index,
command.start_index + command.index_count, command.index_count);
context_->Draw(command.index_count, 0);
}
return 0;
}
int D3D11GraphicsDriver::UpdateState(const DrawCommand& command) {
SCOPE_profile_cpu_f("gpu");
// 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 = register_file_[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32;
uint32_t window_scissor_br = register_file_[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 = register_file_[XE_GPU_REG_RB_MODECONTROL].u32 & 0x7;
// 4 = color + depth
// 6 = copy ?
// color_info[0-3] has format 8888
uint32_t color_info[4] = {
register_file_[XE_GPU_REG_RB_COLOR_INFO].u32,
register_file_[XE_GPU_REG_RB_COLOR1_INFO].u32,
register_file_[XE_GPU_REG_RB_COLOR2_INFO].u32,
register_file_[XE_GPU_REG_RB_COLOR3_INFO].u32,
};
ID3D11RenderTargetView* render_target_views[4] = { 0 };
for (int n = 0; n < poly::countof(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 = register_file_[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);
// Viewport.
// If we have resized the window we will want to change this.
uint32_t window_offset = register_file_[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 = register_file_[XE_GPU_REG_PA_CL_VTE_CNTL].u32;
bool vport_xscale_enable = (vte_control & (1 << 0)) > 0;
float vport_xscale = register_file_[XE_GPU_REG_PA_CL_VPORT_XSCALE].f32; // 640
bool vport_xoffset_enable = (vte_control & (1 << 1)) > 0;
float vport_xoffset = register_file_[XE_GPU_REG_PA_CL_VPORT_XOFFSET].f32; // 640
bool vport_yscale_enable = (vte_control & (1 << 2)) > 0;
float vport_yscale = register_file_[XE_GPU_REG_PA_CL_VPORT_YSCALE].f32; // -360
bool vport_yoffset_enable = (vte_control & (1 << 3)) > 0;
float vport_yoffset = register_file_[XE_GPU_REG_PA_CL_VPORT_YOFFSET].f32; // 360
bool vport_zscale_enable = (vte_control & (1 << 4)) > 0;
float vport_zscale = register_file_[XE_GPU_REG_PA_CL_VPORT_ZSCALE].f32; // 1
bool vport_zoffset_enable = (vte_control & (1 << 5)) > 0;
float vport_zoffset = register_file_[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 = register_file_[XE_GPU_REG_PA_SC_SCREEN_SCISSOR_TL].u32;
uint32_t screen_scissor_br = register_file_[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);
}
if (SetupRasterizerState(command)) {
XELOGE("Unable to setup rasterizer state");
return 1;
}
if (SetupBlendState(command)) {
XELOGE("Unable to setup blend state");
return 1;
}
if (SetupDepthStencilState(command)) {
XELOGE("Unable to setup depth/stencil state");
return 1;
}
return 0;
}
int D3D11GraphicsDriver::SetupRasterizerState(const DrawCommand& command) {
uint32_t mode_control = register_file_[XE_GPU_REG_PA_SU_SC_MODE_CNTL].u32;
// Check cache.
uint64_t key = hash_combine(mode_control);
ID3D11RasterizerState* rasterizer_state = nullptr;
auto it = rasterizer_state_cache_.find(key);
if (it == rasterizer_state_cache_.end()) {
D3D11_RASTERIZER_DESC 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 (command.prim_type == XE_GPU_PRIMITIVE_TYPE_RECTANGLE_LIST) {
// Rect lists aren't culled. There may be other things they skip too.
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;
device_->CreateRasterizerState(&rasterizer_desc, &rasterizer_state);
rasterizer_state_cache_.insert({ key, rasterizer_state });
} else {
rasterizer_state = it->second;
}
context_->RSSetState(rasterizer_state);
return 0;
}
int D3D11GraphicsDriver::SetupBlendState(const DrawCommand& command) {
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 = register_file_[XE_GPU_REG_RB_COLORCONTROL].u32;
uint32_t color_mask = register_file_[XE_GPU_REG_RB_COLOR_MASK].u32;
uint32_t blend_control[4] = {
register_file_[XE_GPU_REG_RB_BLENDCONTROL_0].u32,
register_file_[XE_GPU_REG_RB_BLENDCONTROL_1].u32,
register_file_[XE_GPU_REG_RB_BLENDCONTROL_2].u32,
register_file_[XE_GPU_REG_RB_BLENDCONTROL_3].u32,
};
// Check cache.
uint64_t key = hash_combine(color_mask,
blend_control[0], blend_control[1],
blend_control[2], blend_control[3]);
ID3D11BlendState* blend_state = nullptr;
auto it = blend_state_cache_.find(key);
if (it == blend_state_cache_.end()) {
D3D11_BLEND_DESC blend_desc = {0};
//blend_desc.AlphaToCoverageEnable = false;
// ?
blend_desc.IndependentBlendEnable = true;
for (int n = 0; n < poly::countof(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));
}
device_->CreateBlendState(&blend_desc, &blend_state);
blend_state_cache_.insert({ key, blend_state });
} else {
blend_state = it->second;
}
float blend_factor[4] = {
register_file_[XE_GPU_REG_RB_BLEND_RED].f32,
register_file_[XE_GPU_REG_RB_BLEND_GREEN].f32,
register_file_[XE_GPU_REG_RB_BLEND_BLUE].f32,
register_file_[XE_GPU_REG_RB_BLEND_ALPHA].f32,
};
uint32_t sample_mask = 0xFFFFFFFF; // ?
context_->OMSetBlendState(blend_state, blend_factor, sample_mask);
return 0;
}
int D3D11GraphicsDriver::SetupDepthStencilState(const DrawCommand& command) {
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,
};
uint32_t depth_control = register_file_[XE_GPU_REG_RB_DEPTHCONTROL].u32;
uint32_t stencil_ref_mask = register_file_[XE_GPU_REG_RB_STENCILREFMASK].u32;
// Check cache.
uint64_t key = (uint64_t(depth_control) << 32) | stencil_ref_mask;
ID3D11DepthStencilState* depth_stencil_state = nullptr;
auto it = depth_stencil_state_cache_.find(key);
if (it == depth_stencil_state_cache_.end()) {
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc = {0};
// 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];
device_->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state);
depth_stencil_state_cache_.insert({ key, depth_stencil_state });
} else {
depth_stencil_state = it->second;
}
// RB_STENCILREFMASK_STENCILREF
uint32_t stencil_ref = (stencil_ref_mask & 0x000000FF);
context_->OMSetDepthStencilState(depth_stencil_state, stencil_ref);
return 0;
}
int D3D11GraphicsDriver::SetupConstantBuffers(const DrawCommand& command) {
SCOPE_profile_cpu_f("gpu");
D3D11_MAPPED_SUBRESOURCE res;
context_->Map(
state_.constant_buffers.float_constants, 0,
D3D11_MAP_WRITE_DISCARD, 0, &res);
memcpy(res.pData,
command.float4_constants.values,
command.float4_constants.count * 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,
command.loop_constants.values,
command.loop_constants.count * 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,
command.bool_constants.values,
command.bool_constants.count * sizeof(int));
context_->Unmap(state_.constant_buffers.bool_constants, 0);
return 0;
}
int D3D11GraphicsDriver::SetupShaders(const DrawCommand& command) {
SCOPE_profile_cpu_f("gpu");
if (command.vertex_shader) {
context_->VSSetShader(
command.vertex_shader->handle_as<ID3D11VertexShader>(), nullptr, 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, static_cast<UINT>(poly::countof(vs_constant_buffers)),
vs_constant_buffers);
// Setup input layout (as encoded in vertex shader).
auto vs = static_cast<D3D11VertexShaderResource*>(command.vertex_shader);
context_->IASetInputLayout(vs->input_layout());
} else {
context_->VSSetShader(nullptr, nullptr, 0);
context_->IASetInputLayout(nullptr);
return 1;
}
// Pixel shader setup.
if (command.pixel_shader) {
context_->PSSetShader(
command.pixel_shader->handle_as<ID3D11PixelShader>(), nullptr, 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, static_cast<UINT>(poly::countof(vs_constant_buffers)),
vs_constant_buffers);
} else {
context_->PSSetShader(nullptr, nullptr, 0);
return 1;
}
return 0;
}
int D3D11GraphicsDriver::SetupInputAssembly(const DrawCommand& command) {
SCOPE_profile_cpu_f("gpu");
auto vs = static_cast<D3D11VertexShaderResource*>(command.vertex_shader);
if (!vs) {
return 1;
}
// Switch primitive topology.
// Some are unsupported on D3D11 and must be emulated.
D3D11_PRIMITIVE_TOPOLOGY primitive_topology;
D3D11GeometryShader* geometry_shader = NULL;
switch (command.prim_type) {
case XE_GPU_PRIMITIVE_TYPE_POINT_LIST:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST;
if (vs->DemandGeometryShader(
D3D11VertexShaderResource::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 (vs->DemandGeometryShader(
D3D11VertexShaderResource::RECT_LIST_SHADER, &geometry_shader)) {
return 1;
}
break;
case XE_GPU_PRIMITIVE_TYPE_QUAD_LIST:
primitive_topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ;
if (vs->DemandGeometryShader(
D3D11VertexShaderResource::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", command.prim_type);
break;
}
context_->IASetPrimitiveTopology(primitive_topology);
// Set the geometry shader, if we are emulating a primitive type.
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);
}
// Index buffer, if any. May be auto draw.
if (command.index_buffer) {
DXGI_FORMAT format;
switch (command.index_buffer->info().format) {
case INDEX_FORMAT_16BIT:
format = DXGI_FORMAT_R16_UINT;
break;
case INDEX_FORMAT_32BIT:
format = DXGI_FORMAT_R32_UINT;
break;
}
context_->IASetIndexBuffer(
command.index_buffer->handle_as<ID3D11Buffer>(),
format, 0);
} else {
context_->IASetIndexBuffer(nullptr, DXGI_FORMAT_UNKNOWN, 0);
}
// All vertex buffers.
for (auto i = 0; i < command.vertex_buffer_count; ++i) {
const auto& vb = command.vertex_buffers[i];
auto buffer = vb.buffer->handle_as<ID3D11Buffer>();
auto stride = vb.stride;
auto offset = vb.offset;
context_->IASetVertexBuffers(vb.input_index, 1, &buffer,
&stride, &offset);
}
return 0;
}
int D3D11GraphicsDriver::SetupSamplers(const DrawCommand& command) {
SCOPE_profile_cpu_f("gpu");
for (auto i = 0; i < command.vertex_shader_sampler_count; ++i) {
const auto& input = command.vertex_shader_samplers[i];
if (input.texture) {
auto texture = input.texture->handle_as<ID3D11ShaderResourceView>();
context_->VSSetShaderResources(input.input_index, 1, &texture);
} else {
context_->VSSetShaderResources(input.input_index, 1, &invalid_texture_view_);
}
if (input.sampler_state) {
auto sampler_state = input.sampler_state->handle_as<ID3D11SamplerState>();
context_->VSSetSamplers(input.input_index, 1, &sampler_state);
} else {
context_->VSSetSamplers(input.input_index, 1, &invalid_texture_sampler_state_);
}
}
for (auto i = 0; i < command.pixel_shader_sampler_count; ++i) {
const auto& input = command.pixel_shader_samplers[i];
if (input.texture) {
auto texture = input.texture->handle_as<ID3D11ShaderResourceView>();
context_->PSSetShaderResources(input.input_index, 1, &texture);
} else {
context_->PSSetShaderResources(input.input_index, 1, &invalid_texture_view_);
}
if (input.sampler_state) {
auto sampler_state = input.sampler_state->handle_as<ID3D11SamplerState>();
context_->PSSetSamplers(input.input_index, 1, &sampler_state);
} else {
context_->PSSetSamplers(input.input_index, 1, &invalid_texture_sampler_state_);
}
}
return 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;
}
SCOPE_profile_cpu_f("gpu");
// Remove old versions.
for (int n = 0; n < poly::countof(render_targets_.color_buffers); n++) {
auto& cb = render_targets_.color_buffers[n];
SafeRelease(cb.buffer);
SafeRelease(cb.color_view_8888);
}
SafeRelease(render_targets_.depth_buffer);
SafeRelease(render_targets_.depth_view_d28s8);
SafeRelease(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 < poly::countof(render_targets_.color_buffers); n++) {
auto& cb = render_targets_.color_buffers[n];
D3D11_TEXTURE2D_DESC 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;
memset(&render_target_view_desc, 0, 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 = {};
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 = {};
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::Resolve() {
SCOPE_profile_cpu_f("gpu");
// 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.
}
SafeRelease(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;
}

View File

@ -1,94 +0,0 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_GRAPHICS_DRIVER_H_
#define XENIA_GPU_D3D11_D3D11_GRAPHICS_DRIVER_H_
#include <xenia/common.h>
#include <xenia/gpu/graphics_driver.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_resource_cache.h>
#include <xenia/gpu/xenos/xenos.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11GraphicsDriver : public GraphicsDriver {
public:
D3D11GraphicsDriver(
Memory* memory, IDXGISwapChain* swap_chain, ID3D11Device* device);
virtual ~D3D11GraphicsDriver();
ResourceCache* resource_cache() const override { return resource_cache_; }
int Initialize() override;
int Draw(const DrawCommand& command) override;
// TODO(benvanik): figure this out.
int Resolve() override;
private:
void InitializeInvalidTexture();
int UpdateState(const DrawCommand& command);
int SetupRasterizerState(const DrawCommand& command);
int SetupBlendState(const DrawCommand& command);
int SetupDepthStencilState(const DrawCommand& command);
int SetupConstantBuffers(const DrawCommand& command);
int SetupShaders(const DrawCommand& command);
int SetupInputAssembly(const DrawCommand& command);
int SetupSamplers(const DrawCommand& command);
int RebuildRenderTargets(uint32_t width, uint32_t height);
private:
IDXGISwapChain* swap_chain_;
ID3D11Device* device_;
ID3D11DeviceContext* context_;
D3D11ResourceCache* resource_cache_;
ID3D11ShaderResourceView* invalid_texture_view_;
ID3D11SamplerState* invalid_texture_sampler_state_;
std::unordered_map<uint64_t, ID3D11RasterizerState*> rasterizer_state_cache_;
std::unordered_map<uint64_t, ID3D11BlendState*> blend_state_cache_;
std::unordered_map<uint64_t, ID3D11DepthStencilState*> depth_stencil_state_cache_;
struct {
uint32_t width;
uint32_t height;
struct {
ID3D11Texture2D* buffer;
ID3D11RenderTargetView* color_view_8888;
} color_buffers[4];
ID3D11Texture2D* depth_buffer;
ID3D11DepthStencilView* depth_view_d28s8;
ID3D11DepthStencilView* depth_view_d28fs8;
} render_targets_;
struct {
struct {
ID3D11Buffer* float_constants;
ID3D11Buffer* bool_constants;
ID3D11Buffer* loop_constants;
ID3D11Buffer* vs_consts;
ID3D11Buffer* gs_consts;
} constant_buffers;
} state_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_GRAPHICS_DRIVER_H_

View File

@ -1,200 +0,0 @@
/**
******************************************************************************
* 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_system.h>
#include <chrono>
#include <poly/math.h>
#include <xenia/emulator.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_graphics_driver.h>
#include <xenia/gpu/d3d11/d3d11_window.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
D3D11GraphicsSystem::D3D11GraphicsSystem(Emulator* emulator)
: GraphicsSystem(emulator),
window_(nullptr), dxgi_factory_(nullptr), device_(nullptr),
timer_queue_(nullptr), vsync_timer_(nullptr) {
}
D3D11GraphicsSystem::~D3D11GraphicsSystem() {
}
void D3D11GraphicsSystem::Initialize() {
GraphicsSystem::Initialize();
assert_null(timer_queue_);
assert_null(vsync_timer_);
timer_queue_ = CreateTimerQueue();
CreateTimerQueueTimer(
&vsync_timer_,
timer_queue_,
(WAITORTIMERCALLBACK)VsyncCallback,
this,
16,
16,
WT_EXECUTEINTIMERTHREAD);
// Create DXGI factory so we can get a swap chain/etc.
HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1),
(void**)&dxgi_factory_);
if (FAILED(hr)) {
XELOGE("CreateDXGIFactory1 failed with %.8X", hr);
exit(1);
return;
}
// Find the best adapter.
// TODO(benvanik): enable nvperfhud/etc.
IDXGIAdapter1* adapter = 0;
UINT n = 0;
while (dxgi_factory_->EnumAdapters1(n, &adapter) != DXGI_ERROR_NOT_FOUND) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
adapter->Release();
n++;
}
// Just go with the default for now.
adapter = 0;
D3D_DRIVER_TYPE driver_type =
adapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE;
UINT flags = 0;
// TODO(benvanik): runtime flag
flags |= D3D11_CREATE_DEVICE_DEBUG;
// Feature level 11.0+ only.
D3D_FEATURE_LEVEL feature_levels[] = {
D3D_FEATURE_LEVEL_11_0,
};
// Create device.
D3D_FEATURE_LEVEL actual_feature_level;
ID3D11DeviceContext* immediate_context;
hr = D3D11CreateDevice(
adapter,
driver_type,
0, // software driver HMODULE
flags,
feature_levels,
static_cast<UINT>(poly::countof(feature_levels)),
D3D11_SDK_VERSION,
&device_,
&actual_feature_level,
&immediate_context);
if (adapter) {
adapter->Release();
adapter = 0;
}
if (immediate_context) {
immediate_context->Release();
immediate_context = 0;
}
if (FAILED(hr)) {
XELOGE("D3D11CreateDevice failed with %.8X", hr);
exit(1);
return;
}
// Create the window.
// This will pump through the run-loop and and be where our swapping
// will take place.
assert_null(window_);
window_ = new D3D11Window(run_loop_, dxgi_factory_, device_);
if (window_->Initialize(L"Xenia D3D11", 1280, 720)) {
XELOGE("Failed to create D3D11Window");
exit(1);
return;
}
emulator_->set_main_window(window_);
// Listen for alt-enter/etc.
dxgi_factory_->MakeWindowAssociation(window_->handle(), 0);
// Create the driver.
// This runs in the worker thread and builds command lines to present
// in the window.
assert_null(driver_);
driver_ = new D3D11GraphicsDriver(
memory_, window_->swap_chain(), device_);
if (driver_->Initialize()) {
XELOGE("Unable to initialize D3D11 driver");
return;
}
// Initial vsync kick.
DispatchInterruptCallback(0);
}
void D3D11GraphicsSystem::Pump() {
SCOPE_profile_cpu_f("gpu");
auto time_since_last_swap = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::high_resolution_clock::now() - last_swap_time_);
if (time_since_last_swap.count() > 1) {
// Force a swap when profiling.
if (Profiler::is_enabled()) {
window_->Swap();
}
}
}
void D3D11GraphicsSystem::Swap() {
// TODO(benvanik): remove this when commands are understood.
driver_->Resolve();
// Swap window.
// If we are set to vsync this will block.
window_->Swap();
last_swap_time_ = std::chrono::high_resolution_clock::now();
}
void __stdcall D3D11GraphicsSystem::VsyncCallback(D3D11GraphicsSystem* gs,
BOOLEAN) {
static bool thread_name_set = false;
if (!thread_name_set) {
thread_name_set = true;
Profiler::ThreadEnter("VsyncTimer");
}
SCOPE_profile_cpu_f("gpu");
gs->MarkVblank();
// TODO(benvanik): we shouldn't need to do the dispatch here, but there's
// something wrong and the CP will block waiting for code that
// needs to be run in the interrupt.
gs->DispatchInterruptCallback(0);
}
void D3D11GraphicsSystem::Shutdown() {
GraphicsSystem::Shutdown();
if (vsync_timer_) {
DeleteTimerQueueTimer(timer_queue_, vsync_timer_, NULL);
}
if (timer_queue_) {
DeleteTimerQueueEx(timer_queue_, NULL);
}
SafeRelease(device_);
device_ = 0;
SafeRelease(dxgi_factory_);
dxgi_factory_ = 0;
delete window_;
window_ = 0;
}

View File

@ -1,59 +0,0 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_GRAPHICS_SYSTEM_H_
#define XENIA_GPU_D3D11_D3D11_GRAPHICS_SYSTEM_H_
#include <xenia/common.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/graphics_system.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11Window;
std::unique_ptr<GraphicsSystem> Create(Emulator* emulator);
class D3D11GraphicsSystem : public GraphicsSystem {
public:
D3D11GraphicsSystem(Emulator* emulator);
virtual ~D3D11GraphicsSystem();
virtual void Shutdown();
void Swap() override;
protected:
virtual void Initialize();
virtual void Pump();
private:
static void __stdcall VsyncCallback(D3D11GraphicsSystem* gs, BOOLEAN);
IDXGIFactory1* dxgi_factory_;
ID3D11Device* device_;
D3D11Window* window_;
HANDLE timer_queue_;
HANDLE vsync_timer_;
std::chrono::high_resolution_clock::time_point last_swap_time_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_GRAPHICS_SYSTEM_H_

View File

@ -1,661 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_profiler_display.h>
#include <algorithm>
#include <poly/math.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_window.h>
#include <d3dcompiler.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
namespace {
const uint8_t profiler_font[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x10,0x78,0x38,0x78,0x7c,0x7c,0x3c,0x44,0x38,0x04,0x44,0x40,0x44,0x44,0x38,0x78,
0x38,0x78,0x38,0x7c,0x44,0x44,0x44,0x44,0x44,0x7c,0x00,0x00,0x40,0x00,0x04,0x00,
0x18,0x00,0x40,0x10,0x08,0x40,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x38,0x7c,0x08,0x7c,0x1c,0x7c,0x38,0x38,
0x10,0x28,0x28,0x10,0x00,0x20,0x10,0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x04,0x00,0x20,0x38,0x38,0x70,0x00,0x1c,0x10,0x00,0x1c,0x10,0x70,0x30,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x28,0x44,0x44,0x44,0x40,0x40,0x40,0x44,0x10,0x04,0x48,0x40,0x6c,0x44,0x44,0x44,
0x44,0x44,0x44,0x10,0x44,0x44,0x44,0x44,0x44,0x04,0x00,0x00,0x40,0x00,0x04,0x00,
0x24,0x00,0x40,0x00,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x30,0x44,0x04,0x18,0x40,0x20,0x04,0x44,0x44,
0x10,0x28,0x28,0x3c,0x44,0x50,0x10,0x10,0x08,0x54,0x10,0x00,0x00,0x00,0x04,0x00,
0x00,0x08,0x00,0x10,0x44,0x44,0x40,0x40,0x04,0x28,0x00,0x30,0x10,0x18,0x58,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x44,0x44,0x40,0x44,0x40,0x40,0x40,0x44,0x10,0x04,0x50,0x40,0x54,0x64,0x44,0x44,
0x44,0x44,0x40,0x10,0x44,0x44,0x44,0x28,0x28,0x08,0x00,0x38,0x78,0x3c,0x3c,0x38,
0x20,0x38,0x78,0x30,0x18,0x44,0x10,0x6c,0x78,0x38,0x78,0x3c,0x5c,0x3c,0x3c,0x44,
0x44,0x44,0x44,0x44,0x7c,0x00,0x4c,0x10,0x04,0x08,0x28,0x78,0x40,0x08,0x44,0x44,
0x10,0x00,0x7c,0x50,0x08,0x50,0x00,0x20,0x04,0x38,0x10,0x00,0x00,0x00,0x08,0x10,
0x10,0x10,0x7c,0x08,0x08,0x54,0x40,0x20,0x04,0x44,0x00,0x30,0x10,0x18,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x44,0x78,0x40,0x44,0x78,0x78,0x40,0x7c,0x10,0x04,0x60,0x40,0x54,0x54,0x44,0x78,
0x44,0x78,0x38,0x10,0x44,0x44,0x54,0x10,0x10,0x10,0x00,0x04,0x44,0x40,0x44,0x44,
0x78,0x44,0x44,0x10,0x08,0x48,0x10,0x54,0x44,0x44,0x44,0x44,0x60,0x40,0x10,0x44,
0x44,0x44,0x28,0x44,0x08,0x00,0x54,0x10,0x18,0x18,0x48,0x04,0x78,0x10,0x38,0x3c,
0x10,0x00,0x28,0x38,0x10,0x20,0x00,0x20,0x04,0x10,0x7c,0x00,0x7c,0x00,0x10,0x00,
0x00,0x20,0x00,0x04,0x10,0x5c,0x40,0x10,0x04,0x00,0x00,0x60,0x10,0x0c,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x7c,0x44,0x40,0x44,0x40,0x40,0x4c,0x44,0x10,0x04,0x50,0x40,0x44,0x4c,0x44,0x40,
0x54,0x50,0x04,0x10,0x44,0x44,0x54,0x28,0x10,0x20,0x00,0x3c,0x44,0x40,0x44,0x7c,
0x20,0x44,0x44,0x10,0x08,0x70,0x10,0x54,0x44,0x44,0x44,0x44,0x40,0x38,0x10,0x44,
0x44,0x54,0x10,0x44,0x10,0x00,0x64,0x10,0x20,0x04,0x7c,0x04,0x44,0x20,0x44,0x04,
0x10,0x00,0x7c,0x14,0x20,0x54,0x00,0x20,0x04,0x38,0x10,0x10,0x00,0x00,0x20,0x10,
0x10,0x10,0x7c,0x08,0x10,0x58,0x40,0x08,0x04,0x00,0x00,0x30,0x10,0x18,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x44,0x44,0x44,0x44,0x40,0x40,0x44,0x44,0x10,0x44,0x48,0x40,0x44,0x44,0x44,0x40,
0x48,0x48,0x44,0x10,0x44,0x28,0x6c,0x44,0x10,0x40,0x00,0x44,0x44,0x40,0x44,0x40,
0x20,0x3c,0x44,0x10,0x08,0x48,0x10,0x54,0x44,0x44,0x44,0x44,0x40,0x04,0x12,0x4c,
0x28,0x54,0x28,0x3c,0x20,0x00,0x44,0x10,0x40,0x44,0x08,0x44,0x44,0x20,0x44,0x08,
0x00,0x00,0x28,0x78,0x44,0x48,0x00,0x10,0x08,0x54,0x10,0x10,0x00,0x00,0x40,0x00,
0x10,0x08,0x00,0x10,0x00,0x40,0x40,0x04,0x04,0x00,0x00,0x30,0x10,0x18,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x44,0x78,0x38,0x78,0x7c,0x40,0x3c,0x44,0x38,0x38,0x44,0x7c,0x44,0x44,0x38,0x40,
0x34,0x44,0x38,0x10,0x38,0x10,0x44,0x44,0x10,0x7c,0x00,0x3c,0x78,0x3c,0x3c,0x3c,
0x20,0x04,0x44,0x38,0x48,0x44,0x38,0x44,0x44,0x38,0x78,0x3c,0x40,0x78,0x0c,0x34,
0x10,0x6c,0x44,0x04,0x7c,0x00,0x38,0x38,0x7c,0x38,0x08,0x38,0x38,0x20,0x38,0x70,
0x10,0x00,0x28,0x10,0x00,0x34,0x00,0x08,0x10,0x10,0x00,0x20,0x00,0x10,0x00,0x00,
0x20,0x04,0x00,0x20,0x10,0x3c,0x70,0x00,0x1c,0x00,0x7c,0x1c,0x10,0x70,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x38,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
const char* shader_code = " \
cbuffer MatrixBuffer {\n \
float4x4 projection_matrix;\n \
};\n \
Texture2D texture0;\n \
SamplerState sampler0;\n \
struct Vertex {\n \
float2 position : POSITION0;\n \
float2 tex : TEXCOORD0;\n \
float4 color : COLOR0;\n \
};\n \
struct Pixel {\n \
float4 position : SV_POSITION;\n \
float2 tex : TEXCOORD0;\n \
float4 color : COLOR0;\n \
};\n \
Pixel vs(Vertex v) {\n \
Pixel p;\n \
p.position = float4(mul(float4(v.position, 0.0f, 1.0f), projection_matrix).xy - float2(1.0f, -1.0f), 0.0f, 1.0f);\n \
p.tex = v.tex;\n \
p.color = v.color;\n \
return p;\n \
}\n \
float4 ps(Pixel p) : SV_TARGET {\n \
if (p.tex.x > 1.0f) {\n \
return float4(p.color.rgb, 0.5f);\n \
} else {\n \
float4 sample = texture0.Sample(sampler0, p.tex);\n \
if(sample.w < 0.5f) {\n \
discard;\n \
}\n \
return p.color * sample;\n \
}\n \
}\n";
} // namespace
D3D11ProfilerDisplay::D3D11ProfilerDisplay(D3D11Window* window) : window_(window) {
draw_state_ = { 0 };
if (!SetupState() ||
!SetupShaders() ||
!SetupFont()) {
// Hrm.
assert_always();
}
// Pass through mouse events.
window->mouse_down.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseDown(
e.button() == xe::ui::MouseEvent::MOUSE_BUTTON_LEFT,
e.button() == xe::ui::MouseEvent::MOUSE_BUTTON_RIGHT);
});
window->mouse_up.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseUp();
});
window->mouse_move.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseMove(e.x(), e.y());
});
window->mouse_wheel.AddListener([](xe::ui::MouseEvent& e) {
Profiler::OnMouseWheel(e.x(), e.y(), -e.dy());
});
// Watch for toggle/mode keys and such.
window->key_down.AddListener([](xe::ui::KeyEvent& e) {
Profiler::OnKeyDown(e.key_code());
});
window->key_up.AddListener([](xe::ui::KeyEvent& e) {
Profiler::OnKeyUp(e.key_code());
});
}
bool D3D11ProfilerDisplay::SetupState() {
HRESULT hr;
auto device = window_->device();
D3D11_BLEND_DESC blend_desc = {0};
blend_desc.RenderTarget[0].BlendEnable = true;
blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO;
blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
blend_desc.RenderTarget[0].RenderTargetWriteMask = 0x0F;
hr = device->CreateBlendState(&blend_desc, &blend_state_);
assert_true(SUCCEEDED(hr));
D3D11_DEPTH_STENCIL_DESC depth_stencil_desc = {0};
depth_stencil_desc.DepthEnable = false;
depth_stencil_desc.StencilEnable = false;
depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
hr = device->CreateDepthStencilState(&depth_stencil_desc, &depth_stencil_state_);
assert_true(SUCCEEDED(hr));
return true;
}
bool D3D11ProfilerDisplay::SetupShaders() {
HRESULT hr;
auto device = window_->device();
ID3DBlob* vs_code_blob = nullptr;
ID3DBlob* vs_errors = nullptr;
hr = D3DCompile(
shader_code, strlen(shader_code),
"D3D11ProfilerDisplay.vs",
nullptr,
nullptr,
"vs",
"vs_5_0",
D3DCOMPILE_ENABLE_STRICTNESS,
0,
&vs_code_blob,
&vs_errors);
if (FAILED(hr)) {
XELOGE("Failed to compile profiler vs: %s",
reinterpret_cast<const char*>(vs_errors->GetBufferPointer()));
return false;
}
hr = device->CreateVertexShader(vs_code_blob->GetBufferPointer(),
vs_code_blob->GetBufferSize(),
nullptr,
&vertex_shader_);
if (FAILED(hr)) {
XELOGE("Failed to create profiler vs");
return false;
}
ID3DBlob* ps_code_blob = nullptr;
ID3DBlob* ps_errors = nullptr;
hr = D3DCompile(
shader_code, strlen(shader_code),
"D3D11ProfilerDisplay.ps",
nullptr,
nullptr,
"ps",
"ps_5_0",
D3DCOMPILE_ENABLE_STRICTNESS,
0,
&ps_code_blob,
&ps_errors);
if (FAILED(hr)) {
XELOGE("Failed to compile profiler ps: %s",
reinterpret_cast<const char*>(ps_errors->GetBufferPointer()));
return false;
}
hr = device->CreatePixelShader(ps_code_blob->GetBufferPointer(),
ps_code_blob->GetBufferSize(),
nullptr,
&pixel_shader_);
if (FAILED(hr)) {
XELOGE("Failed to create profiler ps");
return false;
}
D3D11_BUFFER_DESC buffer_desc = { 0 };
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
buffer_desc.ByteWidth = sizeof(float) * 16;
hr = device->CreateBuffer(&buffer_desc, nullptr, &shader_constants_);
if (FAILED(hr)) {
XELOGE("Failed to create profiler constant buffer");
return false;
}
D3D11_INPUT_ELEMENT_DESC element_descs[] = {
{
"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
D3D11_INPUT_PER_VERTEX_DATA, 0,
},
{
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT,
D3D11_INPUT_PER_VERTEX_DATA, 0,
},
{
"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D11_APPEND_ALIGNED_ELEMENT,
D3D11_INPUT_PER_VERTEX_DATA, 0,
},
};
hr = device->CreateInputLayout(
element_descs, (UINT)poly::countof(element_descs),
vs_code_blob->GetBufferPointer(), vs_code_blob->GetBufferSize(),
&shader_layout_);
if (FAILED(hr)) {
XELOGE("Failed to create profiler input layout");
return false;
}
buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
buffer_desc.ByteWidth = sizeof(draw_state_.vertex_buffer);
hr = device->CreateBuffer(&buffer_desc, nullptr, &vertex_buffer_);
if (FAILED(hr)) {
XELOGE("Failed to create profiler vertex buffer");
return false;
}
return true;
}
bool D3D11ProfilerDisplay::SetupFont() {
HRESULT hr;
auto device = window_->device();
// Setup font lookup table.
for (uint32_t i = 0; i < poly::countof(font_description_.char_offsets); ++i) {
font_description_.char_offsets[i] = 206;
}
for (uint32_t i = 'A'; i <= 'Z'; ++i) {
font_description_.char_offsets[i] = (i-'A')*8+1;
}
for (uint32_t i = 'a'; i <= 'z'; ++i) {
font_description_.char_offsets[i] = (i-'a')*8+217;
}
for (uint32_t i = '0'; i <= '9'; ++i) {
font_description_.char_offsets[i] = (i-'0')*8+433;
}
for (uint32_t i = '!'; i <= '/'; ++i) {
font_description_.char_offsets[i] = (i-'!')*8+513;
}
for (uint32_t i = ':'; i <= '@'; ++i) {
font_description_.char_offsets[i] = (i-':')*8+625+8;
}
for (uint32_t i = '['; i <= '_'; ++i) {
font_description_.char_offsets[i] = (i-'[')*8+681+8;
}
for (uint32_t i = '{'; i <= '~'; ++i) {
font_description_.char_offsets[i] = (i-'{')*8+721+8;
}
// Unpack font bitmap into an RGBA texture.
const int FONT_TEX_X = 1024;
const int FONT_TEX_Y = 9;
const int UNPACKED_SIZE = FONT_TEX_X * FONT_TEX_Y * 4;
uint32_t unpacked[UNPACKED_SIZE];
int idx = 0;
int end = FONT_TEX_X * FONT_TEX_Y / 8;
for (int i = 0; i < end; i++) {
uint8_t b = profiler_font[i];
for (int j = 0; j < 8; ++j) {
unpacked[idx++] = b & 0x80 ? 0xFFFFFFFFu : 0;
b <<= 1;
}
}
D3D11_TEXTURE2D_DESC texture_desc = { 0 };
texture_desc.Width = FONT_TEX_X;
texture_desc.Height = FONT_TEX_Y;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texture_desc.SampleDesc.Count = 1;
texture_desc.SampleDesc.Quality = 0;
texture_desc.Usage = D3D11_USAGE_IMMUTABLE;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texture_desc.CPUAccessFlags = 0;
texture_desc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initial_data = { 0 };
initial_data.pSysMem = unpacked;
initial_data.SysMemPitch = FONT_TEX_X * 4;
initial_data.SysMemSlicePitch = 0;
ID3D11Texture2D* font_texture = nullptr;
hr = device->CreateTexture2D(&texture_desc, &initial_data, &font_texture);
if (FAILED(hr)) {
XELOGE("Unable to create profiler font texture");
return false;
}
D3D11_SHADER_RESOURCE_VIEW_DESC texture_view_desc = {};
texture_view_desc.Format = texture_desc.Format;
texture_view_desc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
texture_view_desc.Texture2D.MipLevels = 1;
texture_view_desc.Texture2D.MostDetailedMip = 0;
hr = device->CreateShaderResourceView(
font_texture, &texture_view_desc, &font_texture_view_);
SafeRelease(font_texture);
if (FAILED(hr)) {
XELOGE("Unable to create profiler font texture view");
return false;
}
D3D11_SAMPLER_DESC sampler_desc = {};
sampler_desc.Filter = D3D11_ENCODE_BASIC_FILTER(
D3D11_FILTER_TYPE_POINT, D3D11_FILTER_TYPE_POINT,
D3D11_FILTER_TYPE_POINT, false);
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, &font_sampler_state_);
if (FAILED(hr)) {
PFATAL("D3D11: unable to create invalid sampler state");
return false;
}
return true;
}
D3D11ProfilerDisplay::~D3D11ProfilerDisplay() {
SafeRelease(blend_state_);
SafeRelease(depth_stencil_state_);
SafeRelease(vertex_shader_);
SafeRelease(pixel_shader_);
SafeRelease(shader_constants_);
SafeRelease(shader_layout_);
SafeRelease(font_texture_view_);
SafeRelease(font_sampler_state_);
SafeRelease(vertex_buffer_);
}
uint32_t D3D11ProfilerDisplay::width() const {
return window_->width();
}
uint32_t D3D11ProfilerDisplay::height() const {
return window_->height();
}
void D3D11ProfilerDisplay::Begin() {
auto context = window_->context();
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = static_cast<float>(width());
viewport.Height = static_cast<float>(height());
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
context->RSSetViewports(1, &viewport);
// Setup projection matrix.
float left = viewport.TopLeftX;
float right = viewport.TopLeftX + viewport.Width;
float bottom = viewport.TopLeftY + viewport.Height;
float top = viewport.TopLeftY;
float z_near = viewport.MinDepth;
float z_far = viewport.MaxDepth;
float projection[16] = { 0 };
projection[0] = 2.0f / (right - left);
projection[5] = 2.0f / (top - bottom);
projection[10] = -2.0f / (z_far - z_near);
projection[12] = -(right + left) / (right - left);
projection[13] = -(top + bottom) / (top - bottom);
projection[14] = -(z_far + z_near) / (z_far - z_near);
projection[15] = 1.0f;
D3D11_MAPPED_SUBRESOURCE res;
context->Map(shader_constants_, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
memcpy(res.pData, projection, sizeof(projection));
context->Unmap(shader_constants_, 0);
// Setup state.
context->OMSetBlendState(blend_state_, { 0 }, 0xFFFFFFFF);
context->OMSetDepthStencilState(depth_stencil_state_, 0);
// Bind shaders.
context->GSSetShader(nullptr, nullptr, 0);
context->VSSetShader(vertex_shader_, nullptr, 0);
context->VSSetConstantBuffers(0, 1, &shader_constants_);
context->PSSetShader(pixel_shader_, nullptr, 0);
context->PSSetConstantBuffers(0, 1, &shader_constants_);
ID3D11SamplerState* ps_samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {
font_sampler_state_,
nullptr,
};
context->PSSetSamplers(0, static_cast<UINT>(poly::countof(ps_samplers)),
ps_samplers);
ID3D11ShaderResourceView*
ps_resources[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {
font_texture_view_, nullptr,
};
context->PSSetShaderResources(
0, static_cast<UINT>(poly::countof(ps_resources)), ps_resources);
context->IASetInputLayout(shader_layout_);
}
void D3D11ProfilerDisplay::End() {
Flush();
}
D3D11ProfilerDisplay::Vertex* D3D11ProfilerDisplay::AllocateVertices(
D3D_PRIMITIVE_TOPOLOGY primitive, size_t count) {
if (draw_state_.vertex_index + count >
poly::countof(draw_state_.vertex_buffer)) {
Flush();
}
assert_true(draw_state_.vertex_index + count <=
poly::countof(draw_state_.vertex_buffer));
size_t head = draw_state_.vertex_index;
draw_state_.vertex_index += count;
if (draw_state_.command_index &&
draw_state_.commands[draw_state_.command_index - 1].primitive ==
primitive) {
draw_state_.commands[draw_state_.command_index - 1].vertex_count += count;
} else {
assert_true(draw_state_.command_index <
poly::countof(draw_state_.commands));
draw_state_.commands[draw_state_.command_index].primitive = primitive;
draw_state_.commands[draw_state_.command_index].vertex_count = count;
++draw_state_.command_index;
}
return &draw_state_.vertex_buffer[head];
}
void D3D11ProfilerDisplay::Flush() {
auto context = window_->context();
if (!draw_state_.vertex_index) {
return;
}
D3D11_MAPPED_SUBRESOURCE res;
context->Map(vertex_buffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
memcpy(res.pData, draw_state_.vertex_buffer, sizeof(Vertex) * draw_state_.vertex_index);
context->Unmap(vertex_buffer_, 0);
uint32_t stride = 20;
uint32_t offset = 0;
context->IASetVertexBuffers(0, 1, &vertex_buffer_, &stride, &offset);
size_t vertex_index = 0;
for (int i = 0; i < draw_state_.command_index; ++i) {
size_t count = draw_state_.commands[i].vertex_count;
context->IASetPrimitiveTopology(draw_state_.commands[i].primitive);
context->Draw((UINT)count, (UINT)vertex_index);
vertex_index += count;
}
draw_state_.vertex_index = 0;
draw_state_.command_index = 0;
}
#define Q0(d, member, v) d[0].member = v
#define Q1(d, member, v) d[1].member = v; d[3].member = v
#define Q2(d, member, v) d[4].member = v
#define Q3(d, member, v) d[2].member = v; d[5].member = v
void D3D11ProfilerDisplay::DrawBox(
int x, int y, int x1, int y1, uint32_t color, BoxType type) {
Vertex* v = AllocateVertices(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, 6);
uint32_t color0;
uint32_t color1;
if (type == BOX_TYPE_FLAT) {
color0 = 0xFF000000 |
((color & 0xFF) << 16) |
(color & 0xFF00FF00) |
((color >> 16) & 0xFF);
color1 = color0;
} else {
uint32_t r = 0xFF & (color >> 16);
uint32_t g = 0xFF & (color >> 8);
uint32_t b = 0xFF & color;
uint32_t max_c = std::max(std::max(std::max(r, g), b), 30u);
uint32_t min_c = std::min(std::min(std::min(r, g), b), 180u);
uint32_t r0 = 0xFF & ((r + max_c)/2);
uint32_t g0 = 0xFF & ((g + max_c)/2);
uint32_t b0 = 0xFF & ((b + max_c)/2);
uint32_t r1 = 0xFF & ((r + min_c) / 2);
uint32_t g1 = 0xFF & ((g + min_c) / 2);
uint32_t b1 = 0xFF & ((b + min_c) / 2);
color0 = r0 | (g0 << 8) | (b0 << 16) | (0xFF000000 & color);
color1 = r1 | (g1 << 8) | (b1 << 16) | (0xFF000000 & color);
}
Q0(v, x, (float)x);
Q0(v, y, (float)y);
Q0(v, color, color0);
Q0(v, u, 2.0f);
Q0(v, v, 2.0f);
Q1(v, x, (float)x1);
Q1(v, y, (float)y);
Q1(v, color, color0);
Q1(v, u, 3.0f);
Q1(v, v, 2.0f);
Q2(v, x, (float)x1);
Q2(v, y, (float)y1);
Q2(v, color, color1);
Q2(v, u, 3.0f);
Q2(v, v, 3.0f);
Q3(v, x, (float)x);
Q3(v, y, (float)y1);
Q3(v, color, color1);
Q3(v, u, 2.0f);
Q3(v, v, 3.0f);
}
void D3D11ProfilerDisplay::DrawLine2D(
uint32_t count, float* vertices, uint32_t color) {
if (!count || !vertices) {
return;
}
color = 0xFF000000 |
((color & 0xFF) << 16) |
(color & 0xFF00FF00) |
((color >> 16) & 0xFF);
Vertex* v = AllocateVertices(D3D11_PRIMITIVE_TOPOLOGY_LINELIST, 2 * (count - 1));
for (uint32_t i = 0; i < count - 1; ++i) {
v[0].x = vertices[i * 2];
v[0].y = vertices[i * 2 + 1];
v[0].color = color;
v[0].u = 2.0f;
v[0].v = 2.0f;
v[1].x = vertices[(i + 1) * 2];
v[1].y = vertices[(i + 1) * 2 + 1] ;
v[1].color = color;
v[1].u = 2.0f;
v[1].v = 2.0f;
v += 2;
}
}
void D3D11ProfilerDisplay::DrawText(
int x, int y, uint32_t color, const char* text, size_t text_length) {
const float offset_u = 5.0f / 1024.0f;
float fx = (float)x;
float fy = (float)y;
float fy2 = fy + (MICROPROFILE_TEXT_HEIGHT + 1);
color = 0xFF000000 |
((color & 0xFF) << 16) |
(color & 0xFF00FF00) |
((color >> 16) & 0xFF);
Vertex* v = AllocateVertices(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, 6 * text_length);
const char* s = text;
for (uint32_t j = 0; j < text_length; ++j) {
int16_t nOffset = font_description_.char_offsets[(int)*s++];
float fOffset = nOffset / 1024.f;
Q0(v, x, fx);
Q0(v, y, fy);
Q0(v, color, color);
Q0(v, u, fOffset);
Q0(v, v, 0.0f);
Q1(v, x, fx + MICROPROFILE_TEXT_WIDTH);
Q1(v, y, fy);
Q1(v, color, color);
Q1(v, u, fOffset + offset_u);
Q1(v, v, 0.0f);
Q2(v, x, fx + MICROPROFILE_TEXT_WIDTH);
Q2(v, y, fy2);
Q2(v, color, color);
Q2(v, u, fOffset + offset_u);
Q2(v, v, 1.0f);
Q3(v, x, fx);
Q3(v, y, fy2);
Q3(v, color, color);
Q3(v, u, fOffset);
Q3(v, v, 1.0f);
fx += MICROPROFILE_TEXT_WIDTH + 1;
v += 6;
}
}

View File

@ -1,80 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_PROFILER_DISPLAY_H_
#define XENIA_GPU_D3D11_D3D11_PROFILER_DISPLAY_H_
#include <xenia/common.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11Window;
class D3D11ProfilerDisplay : public ProfilerDisplay {
public:
D3D11ProfilerDisplay(D3D11Window* window);
virtual ~D3D11ProfilerDisplay();
uint32_t width() const override;
uint32_t height() const override;
// TODO(benvanik): GPU timestamping.
void Begin() override;
void End() override;
void DrawBox(int x, int y, int x1, int y1, uint32_t color, BoxType type) override;
void DrawLine2D(uint32_t count, float* vertices, uint32_t color) override;
void DrawText(int x, int y, uint32_t color, const char* text, size_t text_length) override;
private:
bool SetupState();
bool SetupShaders();
bool SetupFont();
struct Vertex {
float x, y;
float u, v;
uint32_t color;
};
struct {
size_t vertex_index;
Vertex vertex_buffer[16 << 10];
struct {
D3D11_PRIMITIVE_TOPOLOGY primitive;
size_t vertex_count;
} commands[32];
size_t command_index;
} draw_state_;
Vertex* AllocateVertices(D3D_PRIMITIVE_TOPOLOGY primitive, size_t count);
void Flush();
D3D11Window* window_;
ID3D11BlendState* blend_state_;
ID3D11DepthStencilState* depth_stencil_state_;
ID3D11VertexShader* vertex_shader_;
ID3D11PixelShader* pixel_shader_;
ID3D11Buffer* shader_constants_;
ID3D11InputLayout* shader_layout_;
ID3D11ShaderResourceView* font_texture_view_;
ID3D11SamplerState* font_sampler_state_;
ID3D11Buffer* vertex_buffer_;
struct {
uint16_t char_offsets[256];
} font_description_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_PROFILER_DISPLAY_H_

View File

@ -1,71 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_resource_cache.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_buffer_resource.h>
#include <xenia/gpu/d3d11/d3d11_sampler_state_resource.h>
#include <xenia/gpu/d3d11/d3d11_shader_resource.h>
#include <xenia/gpu/d3d11/d3d11_texture_resource.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
D3D11ResourceCache::D3D11ResourceCache(Memory* memory,
ID3D11Device* device,
ID3D11DeviceContext* context)
: ResourceCache(memory),
device_(device), context_(context) {
device_->AddRef();
context_->AddRef();
}
D3D11ResourceCache::~D3D11ResourceCache() {
SafeRelease(device_);
SafeRelease(context_);
}
VertexShaderResource* D3D11ResourceCache::CreateVertexShader(
const MemoryRange& memory_range,
const VertexShaderResource::Info& info) {
return new D3D11VertexShaderResource(this, memory_range, info);
}
PixelShaderResource* D3D11ResourceCache::CreatePixelShader(
const MemoryRange& memory_range,
const PixelShaderResource::Info& info) {
return new D3D11PixelShaderResource(this, memory_range, info);
}
TextureResource* D3D11ResourceCache::CreateTexture(
const MemoryRange& memory_range,
const TextureResource::Info& info) {
return new D3D11TextureResource(this, memory_range, info);
}
SamplerStateResource* D3D11ResourceCache::CreateSamplerState(
const SamplerStateResource::Info& info) {
return new D3D11SamplerStateResource(this, info);
}
IndexBufferResource* D3D11ResourceCache::CreateIndexBuffer(
const MemoryRange& memory_range,
const IndexBufferResource::Info& info) {
return new D3D11IndexBufferResource(this, memory_range, info);
}
VertexBufferResource* D3D11ResourceCache::CreateVertexBuffer(
const MemoryRange& memory_range,
const VertexBufferResource::Info& info) {
return new D3D11VertexBufferResource(this, memory_range, info);
}

View File

@ -1,58 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_RESOURCE_CACHE_H_
#define XENIA_GPU_D3D11_D3D11_RESOURCE_CACHE_H_
#include <xenia/common.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/resource_cache.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11ResourceCache : public ResourceCache {
public:
D3D11ResourceCache(Memory* memory,
ID3D11Device* device, ID3D11DeviceContext* context);
virtual ~D3D11ResourceCache();
ID3D11Device* device() const { return device_; }
ID3D11DeviceContext* context() const { return context_; }
protected:
VertexShaderResource* CreateVertexShader(
const MemoryRange& memory_range,
const VertexShaderResource::Info& info) override;
PixelShaderResource* CreatePixelShader(
const MemoryRange& memory_range,
const PixelShaderResource::Info& info) override;
TextureResource* CreateTexture(
const MemoryRange& memory_range,
const TextureResource::Info& info) override;
SamplerStateResource* CreateSamplerState(
const SamplerStateResource::Info& info) override;
IndexBufferResource* CreateIndexBuffer(
const MemoryRange& memory_range,
const IndexBufferResource::Info& info) override;
VertexBufferResource* CreateVertexBuffer(
const MemoryRange& memory_range,
const VertexBufferResource::Info& info) override;
private:
ID3D11Device* device_;
ID3D11DeviceContext* context_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_RESOURCE_CACHE_H_

View File

@ -1,105 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_sampler_state_resource.h>
#include <xenia/gpu/d3d11/d3d11_resource_cache.h>
using namespace std;
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
D3D11SamplerStateResource::D3D11SamplerStateResource(
D3D11ResourceCache* resource_cache, const Info& info)
: SamplerStateResource(info),
resource_cache_(resource_cache),
handle_(nullptr) {
}
D3D11SamplerStateResource::~D3D11SamplerStateResource() {
SafeRelease(handle_);
}
int D3D11SamplerStateResource::Prepare() {
if (handle_) {
return 0;
}
D3D11_SAMPLER_DESC sampler_desc = {};
// MIN, MAG, MIP
static const D3D11_FILTER filter_matrix[2][2][3] = {
{
// min = POINT
{
// mag = POINT
D3D11_FILTER_MIN_MAG_MIP_POINT,
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR,
D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR, // basemap?
},
{
// mag = LINEAR
D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT,
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR,
D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR, // basemap?
},
},
{
// min = LINEAR
{
// mag = POINT
D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT,
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR,
D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR, // basemap?
},
{
// mag = LINEAR
D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT,
D3D11_FILTER_MIN_MAG_MIP_LINEAR,
D3D11_FILTER_MIN_MAG_MIP_LINEAR, // basemap?
},
},
};
sampler_desc.Filter =
filter_matrix[info_.min_filter][info_.mag_filter][info_.mip_filter];
static const D3D11_TEXTURE_ADDRESS_MODE mode_map[] = {
D3D11_TEXTURE_ADDRESS_WRAP,
D3D11_TEXTURE_ADDRESS_MIRROR,
D3D11_TEXTURE_ADDRESS_CLAMP, // ?
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE, // ?
D3D11_TEXTURE_ADDRESS_CLAMP, // ?
D3D11_TEXTURE_ADDRESS_MIRROR_ONCE, // ?
D3D11_TEXTURE_ADDRESS_BORDER, // ?
D3D11_TEXTURE_ADDRESS_MIRROR, // ?
};
sampler_desc.AddressU = mode_map[info_.clamp_u];
sampler_desc.AddressV = mode_map[info_.clamp_v];
sampler_desc.AddressW = mode_map[info_.clamp_w];
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;
HRESULT hr = resource_cache_->device()->CreateSamplerState(
&sampler_desc, &handle_);
if (FAILED(hr)) {
XELOGE("D3D11: unable to create sampler state");
return 1;
}
return 0;
}

View File

@ -1,47 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_SAMPLER_STATE_RESOURCE_H_
#define XENIA_GPU_D3D11_D3D11_SAMPLER_STATE_RESOURCE_H_
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/sampler_state_resource.h>
#include <xenia/gpu/xenos/ucode.h>
#include <xenia/gpu/xenos/xenos.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11ResourceCache;
class D3D11SamplerStateResource : public SamplerStateResource {
public:
D3D11SamplerStateResource(D3D11ResourceCache* resource_cache,
const Info& info);
~D3D11SamplerStateResource() override;
void* handle() const override { return handle_; }
int Prepare() override;
protected:
D3D11ResourceCache* resource_cache_;
ID3D11SamplerState* handle_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_SAMPLER_STATE_RESOURCE_H_

View File

@ -1,375 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_shader_resource.h>
#include <poly/math.h>
#include <xenia/core/hash.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_geometry_shader.h>
#include <xenia/gpu/d3d11/d3d11_resource_cache.h>
#include <xenia/gpu/d3d11/d3d11_shader_translator.h>
#include <xenia/gpu/xenos/ucode.h>
#include <d3dcompiler.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
namespace {
ID3D10Blob* D3D11ShaderCompile(XE_GPU_SHADER_TYPE type,
const char* shader_source,
const char* disasm_source) {
SCOPE_profile_cpu_f("gpu");
// TODO(benvanik): pick shared runtime mode defines.
D3D10_SHADER_MACRO defines[] = {
"TEST_DEFINE", "1",
0, 0,
};
uint32_t flags1 = 0;
flags1 |= D3D10_SHADER_DEBUG;
flags1 |= D3D10_SHADER_ENABLE_STRICTNESS;
uint32_t flags2 = 0;
// Create a name.
const char* base_path = "";
if (FLAGS_dump_shaders.size()) {
base_path = FLAGS_dump_shaders.c_str();
}
size_t hash = hash64(disasm_source, strlen(disasm_source)); // ?
char file_name[poly::max_path];
snprintf(file_name, poly::countof(file_name), "%s/gen_%.16llX.%s", base_path,
hash, type == XE_GPU_SHADER_TYPE_VERTEX ? "vs" : "ps");
if (FLAGS_dump_shaders.size()) {
FILE* f = fopen(file_name, "w");
fprintf(f, shader_source);
fprintf(f, "\n\n");
fprintf(f, "/*\n");
fprintf(f, disasm_source);
fprintf(f, " */\n");
fclose(f);
}
// Compile shader to bytecode blob.
ID3D10Blob* shader_blob = 0;
ID3D10Blob* error_blob = 0;
HRESULT hr = D3DCompile(
shader_source, strlen(shader_source),
file_name,
defines, nullptr,
"main",
type == XE_GPU_SHADER_TYPE_VERTEX ? "vs_5_0" : "ps_5_0",
flags1, flags2,
&shader_blob, &error_blob);
if (error_blob) {
char* msg = (char*)error_blob->GetBufferPointer();
XELOGE("D3D11: shader compile failed with %s", msg);
}
SafeRelease(error_blob);
if (FAILED(hr)) {
return nullptr;
}
return shader_blob;
}
} // namespace
D3D11VertexShaderResource::D3D11VertexShaderResource(
D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info)
: VertexShaderResource(memory_range, info),
resource_cache_(resource_cache),
handle_(nullptr),
input_layout_(nullptr),
translated_src_(nullptr) {
memset(geometry_shaders_, 0, sizeof(geometry_shaders_));
}
D3D11VertexShaderResource::~D3D11VertexShaderResource() {
SafeRelease(handle_);
SafeRelease(input_layout_);
for (int i = 0; i < poly::countof(geometry_shaders_); ++i) {
delete geometry_shaders_[i];
}
free(translated_src_);
}
int D3D11VertexShaderResource::Prepare(
const xe_gpu_program_cntl_t& program_cntl) {
SCOPE_profile_cpu_f("gpu");
if (is_prepared_ || handle_) {
return 0;
}
// TODO(benvanik): look in file based on hash/etc.
void* byte_code = NULL;
size_t byte_code_length = 0;
// Translate and compile source.
D3D11ShaderTranslator translator;
int ret = translator.TranslateVertexShader(this, program_cntl);
if (ret) {
XELOGE("D3D11: failed to translate vertex shader");
return ret;
}
translated_src_ = strdup(translator.translated_src());
ID3D10Blob* shader_blob = D3D11ShaderCompile(
XE_GPU_SHADER_TYPE_VERTEX, translated_src_, disasm_src());
if (!shader_blob) {
return 1;
}
byte_code_length = shader_blob->GetBufferSize();
byte_code = malloc(byte_code_length);
memcpy(byte_code, shader_blob->GetBufferPointer(), byte_code_length);
SafeRelease(shader_blob);
// Create shader.
HRESULT hr = resource_cache_->device()->CreateVertexShader(
byte_code, byte_code_length, nullptr, &handle_);
if (FAILED(hr)) {
XELOGE("D3D11: failed to create vertex shader");
free(byte_code);
return 1;
}
// Create input layout.
ret = CreateInputLayout(byte_code, byte_code_length);
free(byte_code);
if (ret) {
return 1;
}
is_prepared_ = true;
return 0;
}
int D3D11VertexShaderResource::CreateInputLayout(const void* byte_code,
size_t byte_code_length) {
size_t element_count = 0;
const auto& inputs = buffer_inputs();
for (uint32_t n = 0; n < inputs.count; n++) {
element_count += inputs.descs[n].info.element_count;
}
if (!element_count) {
XELOGW("D3D11: vertex shader with zero inputs -- retaining previous values?");
input_layout_ = NULL;
return 0;
}
D3D11_INPUT_ELEMENT_DESC* element_descs = (D3D11_INPUT_ELEMENT_DESC*)alloca(
sizeof(D3D11_INPUT_ELEMENT_DESC) * element_count);
uint32_t el_index = 0;
for (uint32_t n = 0; n < inputs.count; n++) {
const auto& input = inputs.descs[n];
for (uint32_t m = 0; m < input.info.element_count; m++) {
const auto& el = input.info.elements[m];
uint32_t vb_slot = input.input_index;
DXGI_FORMAT vtx_format;
switch (el.format) {
case FMT_8_8_8_8:
if (el.is_normalized) {
vtx_format = el.is_signed ?
DXGI_FORMAT_R8G8B8A8_SNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
} else {
vtx_format = el.is_signed ?
DXGI_FORMAT_R8G8B8A8_SINT : DXGI_FORMAT_R8G8B8A8_UINT;
}
break;
case FMT_2_10_10_10:
if (el.is_normalized) {
vtx_format = DXGI_FORMAT_R10G10B10A2_UNORM;
} else {
vtx_format = DXGI_FORMAT_R10G10B10A2_UINT;
}
break;
// DXGI_FORMAT_R11G11B10_FLOAT?
case FMT_16_16:
if (el.is_normalized) {
vtx_format = el.is_signed ?
DXGI_FORMAT_R16G16_SNORM : DXGI_FORMAT_R16G16_UNORM;
} else {
vtx_format = el.is_signed ?
DXGI_FORMAT_R16G16_SINT : DXGI_FORMAT_R16G16_UINT;
}
break;
case FMT_16_16_16_16:
if (el.is_normalized) {
vtx_format = el.is_signed ?
DXGI_FORMAT_R16G16B16A16_SNORM : DXGI_FORMAT_R16G16B16A16_UNORM;
} else {
vtx_format = el.is_signed ?
DXGI_FORMAT_R16G16B16A16_SINT : DXGI_FORMAT_R16G16B16A16_UINT;
}
break;
case FMT_16_16_FLOAT:
vtx_format = DXGI_FORMAT_R16G16_FLOAT;
break;
case FMT_16_16_16_16_FLOAT:
vtx_format = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
case FMT_32:
vtx_format = el.is_signed ?
DXGI_FORMAT_R32_SINT : DXGI_FORMAT_R32_UINT;
break;
case FMT_32_32:
vtx_format = el.is_signed ?
DXGI_FORMAT_R32G32_SINT : DXGI_FORMAT_R32G32_UINT;
break;
case FMT_32_32_32_32:
vtx_format = el.is_signed ?
DXGI_FORMAT_R32G32B32A32_SINT : DXGI_FORMAT_R32G32B32A32_UINT;
break;
case FMT_32_FLOAT:
vtx_format = DXGI_FORMAT_R32_FLOAT;
break;
case FMT_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32_FLOAT;
break;
case FMT_32_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32B32_FLOAT;
break;
case FMT_32_32_32_32_FLOAT:
vtx_format = DXGI_FORMAT_R32G32B32A32_FLOAT;
break;
default:
assert_always();
break;
}
element_descs[el_index].SemanticName = "XE_VF";
element_descs[el_index].SemanticIndex = el_index;
element_descs[el_index].Format = vtx_format;
element_descs[el_index].InputSlot = vb_slot;
element_descs[el_index].AlignedByteOffset = el.offset_words * 4;
element_descs[el_index].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
element_descs[el_index].InstanceDataStepRate = 0;
el_index++;
}
}
HRESULT hr = resource_cache_->device()->CreateInputLayout(
element_descs,
(UINT)element_count,
byte_code, byte_code_length,
&input_layout_);
if (FAILED(hr)) {
XELOGE("D3D11: failed to create vertex shader input layout");
return 1;
}
return 0;
}
int D3D11VertexShaderResource::DemandGeometryShader(
GeometryShaderType type, D3D11GeometryShader** out_shader) {
if (geometry_shaders_[type]) {
*out_shader = geometry_shaders_[type];
return 0;
}
// Demand generate.
auto device = resource_cache_->device();
D3D11GeometryShader* shader = nullptr;
switch (type) {
case POINT_SPRITE_SHADER:
shader = new D3D11PointSpriteGeometryShader(device);
break;
case RECT_LIST_SHADER:
shader = new D3D11RectListGeometryShader(device);
break;
case QUAD_LIST_SHADER:
shader = new D3D11QuadListGeometryShader(device);
break;
default:
assert_always();
return 1;
}
if (!shader) {
return 1;
}
if (shader->Prepare(this)) {
delete shader;
return 1;
}
geometry_shaders_[type] = shader;
*out_shader = geometry_shaders_[type];
return 0;
}
D3D11PixelShaderResource::D3D11PixelShaderResource(
D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info)
: PixelShaderResource(memory_range, info),
resource_cache_(resource_cache),
handle_(nullptr),
translated_src_(nullptr) {
}
D3D11PixelShaderResource::~D3D11PixelShaderResource() {
SafeRelease(handle_);
free(translated_src_);
}
int D3D11PixelShaderResource::Prepare(const xe_gpu_program_cntl_t& program_cntl,
VertexShaderResource* input_shader) {
SCOPE_profile_cpu_f("gpu");
if (is_prepared_ || handle_) {
return 0;
}
// TODO(benvanik): look in file based on hash/etc.
void* byte_code = NULL;
size_t byte_code_length = 0;
// Translate and compile source.
D3D11ShaderTranslator translator;
int ret = translator.TranslatePixelShader(this,
program_cntl,
input_shader->alloc_counts());
if (ret) {
XELOGE("D3D11: failed to translate pixel shader");
return ret;
}
translated_src_ = strdup(translator.translated_src());
ID3D10Blob* shader_blob = D3D11ShaderCompile(
XE_GPU_SHADER_TYPE_PIXEL, translated_src_, disasm_src());
if (!shader_blob) {
return 1;
}
byte_code_length = shader_blob->GetBufferSize();
byte_code = malloc(byte_code_length);
memcpy(byte_code, shader_blob->GetBufferPointer(), byte_code_length);
SafeRelease(shader_blob);
// Create shader.
HRESULT hr = resource_cache_->device()->CreatePixelShader(
byte_code, byte_code_length,
nullptr,
&handle_);
if (FAILED(hr)) {
XELOGE("D3D11: failed to create pixel shader");
free(byte_code);
return 1;
}
free(byte_code);
is_prepared_ = true;
return 0;
}

View File

@ -1,91 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_SHADER_RESOURCE_H_
#define XENIA_GPU_D3D11_D3D11_SHADER_RESOURCE_H_
#include <xenia/gpu/shader_resource.h>
#include <xenia/gpu/xenos/xenos.h>
#include <d3d11.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11GeometryShader;
class D3D11ResourceCache;
struct Output;
typedef struct {
Output* output;
xenos::XE_GPU_SHADER_TYPE type;
uint32_t tex_fetch_index;
} xe_gpu_translate_ctx_t;
class D3D11VertexShaderResource : public VertexShaderResource {
public:
D3D11VertexShaderResource(D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info);
~D3D11VertexShaderResource() override;
void* handle() const override { return handle_; }
ID3D11InputLayout* input_layout() const { return input_layout_; }
const char* translated_src() const { return translated_src_; }
int Prepare(const xenos::xe_gpu_program_cntl_t& program_cntl) override;
enum GeometryShaderType {
POINT_SPRITE_SHADER,
RECT_LIST_SHADER,
QUAD_LIST_SHADER,
MAX_GEOMETRY_SHADER_TYPE, // keep at the end
};
int DemandGeometryShader(GeometryShaderType type,
D3D11GeometryShader** out_shader);
private:
int CreateInputLayout(const void* byte_code, size_t byte_code_length);
D3D11ResourceCache* resource_cache_;
ID3D11VertexShader* handle_;
ID3D11InputLayout* input_layout_;
D3D11GeometryShader* geometry_shaders_[MAX_GEOMETRY_SHADER_TYPE];
char* translated_src_;
};
class D3D11PixelShaderResource : public PixelShaderResource {
public:
D3D11PixelShaderResource(D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info);
~D3D11PixelShaderResource() override;
void* handle() const override { return handle_; }
const char* translated_src() const { return translated_src_; }
int Prepare(const xenos::xe_gpu_program_cntl_t& program_cntl,
VertexShaderResource* vertex_shader) override;
private:
D3D11ResourceCache* resource_cache_;
ID3D11PixelShader* handle_;
char* translated_src_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_SHADER_RESOURCE_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,125 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_SHADER_TRANSLATOR_H_
#define XENIA_GPU_D3D11_D3D11_SHADER_TRANSLATOR_H_
#include <xenia/gpu/shader_resource.h>
#include <xenia/gpu/xenos/xenos.h>
#include <d3d11.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11ShaderTranslator {
public:
const static uint32_t kMaxInterpolators = 16;
D3D11ShaderTranslator();
int TranslateVertexShader(VertexShaderResource* vertex_shader,
const xenos::xe_gpu_program_cntl_t& program_cntl);
int TranslatePixelShader(
PixelShaderResource* pixel_shader,
const xenos::xe_gpu_program_cntl_t& program_cntl,
const VertexShaderResource::AllocCounts& alloc_counts);
const char* translated_src() const { return buffer_; }
private:
xenos::XE_GPU_SHADER_TYPE type_;
uint32_t tex_fetch_index_;
const uint32_t* dwords_;
static const int kCapacity = 64 * 1024;
char buffer_[kCapacity];
size_t capacity_;
size_t offset_;
void append(const char* format, ...) {
va_list args;
va_start(args, format);
int len = vsnprintf(buffer_ + offset_, capacity_ - offset_, format, args);
va_end(args);
offset_ += len;
buffer_[offset_] = 0;
}
void AppendTextureHeader(
const ShaderResource::SamplerInputs& sampler_inputs);
void AppendSrcReg(uint32_t num, uint32_t type, uint32_t swiz, uint32_t negate,
uint32_t abs);
void AppendDestRegName(uint32_t num, uint32_t dst_exp);
void AppendDestReg(uint32_t num, uint32_t mask, uint32_t dst_exp);
void AppendDestRegPost(uint32_t num, uint32_t mask, uint32_t dst_exp);
void PrintSrcReg(uint32_t num, uint32_t type, uint32_t swiz, uint32_t negate,
uint32_t abs);
void PrintDstReg(uint32_t num, uint32_t mask, uint32_t dst_exp);
void PrintExportComment(uint32_t num);
int TranslateALU(const xenos::instr_alu_t* alu, int sync);
int TranslateALU_ADDv(const xenos::instr_alu_t& alu);
int TranslateALU_MULv(const xenos::instr_alu_t& alu);
int TranslateALU_MAXv(const xenos::instr_alu_t& alu);
int TranslateALU_MINv(const xenos::instr_alu_t& alu);
int TranslateALU_SETXXv(const xenos::instr_alu_t& alu, const char* op);
int TranslateALU_SETEv(const xenos::instr_alu_t& alu);
int TranslateALU_SETGTv(const xenos::instr_alu_t& alu);
int TranslateALU_SETGTEv(const xenos::instr_alu_t& alu);
int TranslateALU_SETNEv(const xenos::instr_alu_t& alu);
int TranslateALU_FRACv(const xenos::instr_alu_t& alu);
int TranslateALU_TRUNCv(const xenos::instr_alu_t& alu);
int TranslateALU_FLOORv(const xenos::instr_alu_t& alu);
int TranslateALU_MULADDv(const xenos::instr_alu_t& alu);
int TranslateALU_CNDXXv(const xenos::instr_alu_t& alu, const char* op);
int TranslateALU_CNDEv(const xenos::instr_alu_t& alu);
int TranslateALU_CNDGTEv(const xenos::instr_alu_t& alu);
int TranslateALU_CNDGTv(const xenos::instr_alu_t& alu);
int TranslateALU_DOT4v(const xenos::instr_alu_t& alu);
int TranslateALU_DOT3v(const xenos::instr_alu_t& alu);
int TranslateALU_DOT2ADDv(const xenos::instr_alu_t& alu);
// CUBEv
int TranslateALU_MAX4v(const xenos::instr_alu_t& alu);
// ...
int TranslateALU_MAXs(const xenos::instr_alu_t& alu);
int TranslateALU_MINs(const xenos::instr_alu_t& alu);
int TranslateALU_SETXXs(const xenos::instr_alu_t& alu, const char* op);
int TranslateALU_SETEs(const xenos::instr_alu_t& alu);
int TranslateALU_SETGTs(const xenos::instr_alu_t& alu);
int TranslateALU_SETGTEs(const xenos::instr_alu_t& alu);
int TranslateALU_SETNEs(const xenos::instr_alu_t& alu);
int TranslateALU_RECIP_IEEE(const xenos::instr_alu_t& alu);
int TranslateALU_MUL_CONST_0(const xenos::instr_alu_t& alu);
int TranslateALU_MUL_CONST_1(const xenos::instr_alu_t& alu);
int TranslateALU_ADD_CONST_0(const xenos::instr_alu_t& alu);
int TranslateALU_ADD_CONST_1(const xenos::instr_alu_t& alu);
int TranslateALU_SUB_CONST_0(const xenos::instr_alu_t& alu);
int TranslateALU_SUB_CONST_1(const xenos::instr_alu_t& alu);
int TranslateALU_RETAIN_PREV(const xenos::instr_alu_t& alu);
void PrintDestFecth(uint32_t dst_reg, uint32_t dst_swiz);
void AppendFetchDest(uint32_t dst_reg, uint32_t dst_swiz);
int GetFormatComponentCount(uint32_t format);
int TranslateExec(const xenos::instr_cf_exec_t& cf);
int TranslateVertexFetch(const xenos::instr_fetch_vtx_t* vtx, int sync);
int TranslateTextureFetch(const xenos::instr_fetch_tex_t* tex, int sync);
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_SHADER_TRANSLATOR_H_

View File

@ -1,216 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/gpu/d3d11/d3d11_texture_resource.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_resource_cache.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
D3D11TextureResource::D3D11TextureResource(
D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info)
: TextureResource(memory_range, info),
resource_cache_(resource_cache),
texture_(nullptr),
handle_(nullptr) {
}
D3D11TextureResource::~D3D11TextureResource() {
SafeRelease(texture_);
SafeRelease(handle_);
}
int D3D11TextureResource::CreateHandle() {
SCOPE_profile_cpu_f("gpu");
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
// TODO(benvanik): this may need to be typed on the fetch instruction (float/int/etc?)
srv_desc.Format = info_.format;
D3D_SRV_DIMENSION dimension = D3D11_SRV_DIMENSION_UNKNOWN;
switch (info_.dimension) {
case TEXTURE_DIMENSION_1D:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
srv_desc.Texture1D.MipLevels = 1;
srv_desc.Texture1D.MostDetailedMip = 0;
if (CreateHandle1D()) {
XELOGE("D3D11: failed to create Texture1D");
return 1;
}
break;
case TEXTURE_DIMENSION_2D:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = 1;
srv_desc.Texture2D.MostDetailedMip = 0;
if (CreateHandle2D()) {
XELOGE("D3D11: failed to create Texture2D");
return 1;
}
break;
case TEXTURE_DIMENSION_3D:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srv_desc.Texture3D.MipLevels = 1;
srv_desc.Texture3D.MostDetailedMip = 0;
if (CreateHandle3D()) {
XELOGE("D3D11: failed to create Texture3D");
return 1;
}
break;
case TEXTURE_DIMENSION_CUBE:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srv_desc.TextureCube.MipLevels = 1;
srv_desc.TextureCube.MostDetailedMip = 0;
if (CreateHandleCube()) {
XELOGE("D3D11: failed to create TextureCube");
return 1;
}
break;
}
HRESULT hr = resource_cache_->device()->CreateShaderResourceView(
texture_, &srv_desc, &handle_);
if (FAILED(hr)) {
XELOGE("D3D11: unable to create texture resource view");
return 1;
}
return 0;
}
int D3D11TextureResource::CreateHandle1D() {
uint32_t width = 1 + info_.size_1d.width;
D3D11_TEXTURE1D_DESC 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 = resource_cache_->device()->CreateTexture1D(
&texture_desc, NULL, (ID3D11Texture1D**)&texture_);
if (FAILED(hr)) {
return 1;
}
return 0;
}
int D3D11TextureResource::CreateHandle2D() {
D3D11_TEXTURE2D_DESC texture_desc = {};
texture_desc.Width = info_.size_2d.output_width;
texture_desc.Height = info_.size_2d.output_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 = resource_cache_->device()->CreateTexture2D(
&texture_desc, NULL, (ID3D11Texture2D**)&texture_);
if (FAILED(hr)) {
return 1;
}
return 0;
}
int D3D11TextureResource::CreateHandle3D() {
XELOGE("D3D11: CreateTexture3D not yet implemented");
assert_always();
return 1;
}
int D3D11TextureResource::CreateHandleCube() {
XELOGE("D3D11: CreateTextureCube not yet implemented");
assert_always();
return 1;
}
int D3D11TextureResource::InvalidateRegion(const MemoryRange& memory_range) {
SCOPE_profile_cpu_f("gpu");
switch (info_.dimension) {
case TEXTURE_DIMENSION_1D:
return InvalidateRegion1D(memory_range);
case TEXTURE_DIMENSION_2D:
return InvalidateRegion2D(memory_range);
case TEXTURE_DIMENSION_3D:
return InvalidateRegion3D(memory_range);
case TEXTURE_DIMENSION_CUBE:
return InvalidateRegionCube(memory_range);
}
return 1;
}
int D3D11TextureResource::InvalidateRegion1D(const MemoryRange& memory_range) {
return 1;
}
int D3D11TextureResource::InvalidateRegion2D(const MemoryRange& memory_range) {
// TODO(benvanik): all mip levels.
D3D11_MAPPED_SUBRESOURCE res;
HRESULT hr = resource_cache_->context()->Map(
texture_, 0, D3D11_MAP_WRITE_DISCARD, 0, &res);
if (FAILED(hr)) {
XELOGE("D3D11: failed to map texture");
return 1;
}
const uint8_t* src = memory_range_.host_base;
uint8_t* dest = (uint8_t*)res.pData;
uint32_t output_pitch = res.RowPitch; // (output_width / info.block_size) * info.texel_pitch;
if (!info_.is_tiled) {
dest = (uint8_t*)res.pData;
for (uint32_t y = 0; y < info_.size_2d.block_height; y++) {
for (uint32_t x = 0; x < info_.size_2d.logical_pitch; x += info_.texel_pitch) {
TextureSwap(dest + x, src + x, info_.texel_pitch);
}
src += info_.size_2d.input_pitch;
dest += output_pitch;
}
} else {
auto bpp = (info_.texel_pitch >> 2) + ((info_.texel_pitch >> 1) >> (info_.texel_pitch >> 2));
for (uint32_t y = 0, output_base_offset = 0;
y < info_.size_2d.block_height;
y++, output_base_offset += output_pitch) {
auto input_base_offset = TiledOffset2DOuter(y, (info_.size_2d.input_width / info_.block_size), bpp);
for (uint32_t x = 0, output_offset = output_base_offset;
x < info_.size_2d.block_width;
x++, output_offset += info_.texel_pitch) {
auto input_offset = TiledOffset2DInner(x, y, bpp, input_base_offset) >> bpp;
TextureSwap(dest + output_offset,
src + input_offset * info_.texel_pitch,
info_.texel_pitch);
}
}
}
resource_cache_->context()->Unmap(texture_, 0);
return 0;
}
int D3D11TextureResource::InvalidateRegion3D(const MemoryRange& memory_range) {
return 1;
}
int D3D11TextureResource::InvalidateRegionCube(
const MemoryRange& memory_range) {
return 1;
}

View File

@ -1,59 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_TEXTURE_RESOURCE_H_
#define XENIA_GPU_D3D11_D3D11_TEXTURE_RESOURCE_H_
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/gpu/texture_resource.h>
#include <xenia/gpu/xenos/xenos.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11ResourceCache;
class D3D11TextureResource : public TextureResource {
public:
D3D11TextureResource(D3D11ResourceCache* resource_cache,
const MemoryRange& memory_range,
const Info& info);
~D3D11TextureResource() override;
void* handle() const override { return handle_; }
protected:
int CreateHandle() override;
int CreateHandle1D();
int CreateHandle2D();
int CreateHandle3D();
int CreateHandleCube();
int InvalidateRegion(const MemoryRange& memory_range) override;
int InvalidateRegion1D(const MemoryRange& memory_range);
int InvalidateRegion2D(const MemoryRange& memory_range);
int InvalidateRegion3D(const MemoryRange& memory_range);
int InvalidateRegionCube(const MemoryRange& memory_range);
private:
D3D11ResourceCache* resource_cache_;
ID3D11Resource* texture_;
ID3D11ShaderResourceView* handle_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_TEXTURE_RESOURCE_H_

View File

@ -1,140 +0,0 @@
/**
******************************************************************************
* 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_window.h>
#include <xenia/gpu/d3d11/d3d11_profiler_display.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::ui;
using namespace xe::ui::win32;
D3D11Window::D3D11Window(
xe_run_loop_ref run_loop,
IDXGIFactory1* dxgi_factory, ID3D11Device* device) :
Win32Window(run_loop) {
dxgi_factory_ = dxgi_factory;
dxgi_factory_->AddRef();
device_ = device;
device_->AddRef();
device_->GetImmediateContext(&context_);
swap_chain_ = 0;
render_target_view_ = 0;
closing.AddListener([](UIEvent& e) {
xe_run_loop_quit(e.window()->run_loop());
});
}
D3D11Window::~D3D11Window() {
Profiler::set_display(nullptr);
if (context_) {
context_->ClearState();
}
SafeRelease(render_target_view_);
SafeRelease(context_);
SafeRelease(swap_chain_);
SafeRelease(device_);
SafeRelease(dxgi_factory_);
}
int D3D11Window::Initialize(const std::wstring& title, uint32_t width,
uint32_t height) {
int result = Win32Window::Initialize(title, width, height);
if (result) {
return result;
}
// Setup swap chain.
DXGI_SWAP_CHAIN_DESC desc = {};
desc.OutputWindow = handle();
desc.Windowed = TRUE;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
// Setup buffers.
desc.BufferCount = 2;
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferDesc.Width = width;
desc.BufferDesc.Height = height;
desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.BufferDesc.RefreshRate.Numerator = 60;
desc.BufferDesc.RefreshRate.Denominator = 1;
// Disable multisampling.
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
// Create!
HRESULT hr = dxgi_factory_->CreateSwapChain(
device_,
&desc,
&swap_chain_);
if (FAILED(hr)) {
XELOGE("CreateSwapChain failed with %.8X", hr);
return 1;
}
// Create a render target view to draw into.
ID3D11Texture2D* back_buffer = 0;
hr = swap_chain_->GetBuffer(
0, __uuidof(ID3D11Texture2D), (void**)&back_buffer);
if (FAILED(hr)) {
XELOGE("GetBuffer (back_buffer) failed with %.8X", hr);
return 1;
}
hr = device_->CreateRenderTargetView(
back_buffer, NULL, &render_target_view_);
back_buffer->Release();
if (FAILED(hr)) {
XELOGE("CreateRenderTargetView (back_buffer) failed with %.8X", hr);
return 1;
}
context_->OMSetRenderTargets(1, &render_target_view_, NULL);
// Setup profiler display.
if (Profiler::is_enabled()) {
std::unique_ptr<D3D11ProfilerDisplay> profiler_display(
new D3D11ProfilerDisplay(this));
Profiler::set_display(std::move(profiler_display));
}
return 0;
}
void D3D11Window::Swap() {
SCOPE_profile_cpu_f("gpu");
// Present profiler.
context_->OMSetRenderTargets(1, &render_target_view_, NULL);
Profiler::Present();
// Swap buffers.
// TODO(benvanik): control vsync with flag.
bool vsync = true;
HRESULT hr = swap_chain_->Present(vsync ? 1 : 0, 0);
if (FAILED(hr)) {
XELOGE("Present failed with %.8X", hr);
}
}
bool D3D11Window::OnResize(uint32_t width, uint32_t height) {
if (!Win32Window::OnResize(width, height)) {
return false;
}
// TODO(benvanik): resize swap buffers?
return true;
}

View File

@ -1,52 +0,0 @@
/**
******************************************************************************
* 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. *
******************************************************************************
*/
#ifndef XENIA_GPU_D3D11_D3D11_WINDOW_H_
#define XENIA_GPU_D3D11_D3D11_WINDOW_H_
#include <xenia/common.h>
#include <xenia/gpu/d3d11/d3d11_gpu-private.h>
#include <xenia/ui/win32/win32_window.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11Window : public xe::ui::win32::Win32Window {
public:
D3D11Window(
xe_run_loop_ref run_loop,
IDXGIFactory1* dxgi_factory, ID3D11Device* device);
~D3D11Window() override;
ID3D11Device* device() const { return device_; }
IDXGISwapChain* swap_chain() const { return swap_chain_; }
ID3D11DeviceContext* context() const { return context_; }
int Initialize(const std::wstring& title, uint32_t width,
uint32_t height) override;
void Swap();
protected:
bool OnResize(uint32_t width, uint32_t height) override;
private:
IDXGIFactory1* dxgi_factory_;
ID3D11Device* device_;
IDXGISwapChain* swap_chain_;
ID3D11DeviceContext* context_;
ID3D11RenderTargetView* render_target_view_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_WINDOW_H_

View File

@ -1,30 +0,0 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'd3d11_buffer_resource.cc',
'd3d11_buffer_resource.h',
'd3d11_geometry_shader.cc',
'd3d11_geometry_shader.h',
'd3d11_gpu-private.h',
'd3d11_gpu.cc',
'd3d11_gpu.h',
'd3d11_graphics_driver.cc',
'd3d11_graphics_driver.h',
'd3d11_graphics_system.cc',
'd3d11_graphics_system.h',
'd3d11_profiler_display.cc',
'd3d11_profiler_display.h',
'd3d11_resource_cache.cc',
'd3d11_resource_cache.h',
'd3d11_sampler_state_resource.cc',
'd3d11_sampler_state_resource.h',
'd3d11_shader_resource.cc',
'd3d11_shader_resource.h',
'd3d11_shader_translator.cc',
'd3d11_shader_translator.h',
'd3d11_texture_resource.cc',
'd3d11_texture_resource.h',
'd3d11_window.cc',
'd3d11_window.h',
],
}