diff --git a/src/xenia/gpu/buffer.cc b/src/xenia/gpu/buffer.cc new file mode 100644 index 000000000..0b7fe9ad6 --- /dev/null +++ b/src/xenia/gpu/buffer.cc @@ -0,0 +1,40 @@ +/** + ****************************************************************************** + * 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 + +#include + + +using namespace xe; +using namespace xe::gpu; +using namespace xe::gpu::xenos; + + +Buffer::Buffer( + const uint8_t* src_ptr, size_t length) : + src_(src_ptr), length_(length) { +} + +Buffer::~Buffer() { +} + +IndexBuffer::IndexBuffer(const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length) + : Buffer(src_ptr, length), + info_(info) { +} + +IndexBuffer::~IndexBuffer() {} + +VertexBuffer::VertexBuffer(const uint8_t* src_ptr, size_t length) + : Buffer(src_ptr, length) { +} + +VertexBuffer::~VertexBuffer() {} diff --git a/src/xenia/gpu/buffer.h b/src/xenia/gpu/buffer.h new file mode 100644 index 000000000..bc83ed20d --- /dev/null +++ b/src/xenia/gpu/buffer.h @@ -0,0 +1,72 @@ +/** + ****************************************************************************** + * 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_BUFFER_H_ +#define XENIA_GPU_BUFFER_H_ + +#include +#include +#include + + +namespace xe { +namespace gpu { + + +class Buffer { +public: + Buffer(const uint8_t* src_ptr, size_t length); + virtual ~Buffer(); + + const uint8_t* src() const { return src_; } + size_t length() const { return length_; } + uint64_t hash() const { return hash_; } + + virtual bool FetchNew(uint64_t hash) = 0; + virtual bool FetchDirty(uint64_t hash) = 0; + +protected: + const uint8_t* src_; + size_t length_; + uint64_t hash_; +}; + + +struct IndexBufferInfo { + bool index_32bit; + uint32_t index_count; + uint32_t index_size; + uint32_t endianness; +}; + + +class IndexBuffer : public Buffer { +public: + IndexBuffer(const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length); + virtual ~IndexBuffer(); + +protected: + IndexBufferInfo info_; +}; + + +class VertexBuffer : public Buffer { +public: + VertexBuffer(const uint8_t* src_ptr, size_t length); + virtual ~VertexBuffer(); +}; + + + +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_BUFFER_H_ diff --git a/src/xenia/gpu/buffer_cache.cc b/src/xenia/gpu/buffer_cache.cc new file mode 100644 index 000000000..1f1d9ac00 --- /dev/null +++ b/src/xenia/gpu/buffer_cache.cc @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * 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 + +#include + + +using namespace std; +using namespace xe; +using namespace xe::gpu; +using namespace xe::gpu::xenos; + + +BufferCache::BufferCache() { +} + +BufferCache::~BufferCache() { + Clear(); +} + +IndexBuffer* BufferCache::FetchIndexBuffer( + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length) { + size_t key = hash_combine(info.endianness, info.index_32bit, info.index_count, info.index_size); + size_t hash = xe_hash64(src_ptr, length); + auto it = index_buffer_map_.find(key); + if (it != index_buffer_map_.end()) { + if (hash == it->second->hash()) { + return it->second; + } else { + return it->second->FetchDirty(hash) ? it->second : nullptr; + } + } else { + auto buffer = CreateIndexBuffer(info, src_ptr, length); + index_buffer_map_.insert({ key, buffer }); + if (!buffer->FetchNew(hash)) { + return nullptr; + } + return buffer; + } +} + +void BufferCache::Clear() { + for (auto it = index_buffer_map_.begin(); + it != index_buffer_map_.end(); ++it) { + auto buffer = it->second; + delete buffer; + } + index_buffer_map_.clear(); +} diff --git a/src/xenia/gpu/buffer_cache.h b/src/xenia/gpu/buffer_cache.h new file mode 100644 index 000000000..21a057a0c --- /dev/null +++ b/src/xenia/gpu/buffer_cache.h @@ -0,0 +1,47 @@ +/** + ****************************************************************************** + * 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_BUFFER_CACHE_H_ +#define XENIA_GPU_BUFFER_CACHE_H_ + +#include +#include +#include + + +namespace xe { +namespace gpu { + + +class BufferCache { +public: + BufferCache(); + virtual ~BufferCache(); + + IndexBuffer* FetchIndexBuffer( + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length); + + void Clear(); + +protected: + virtual IndexBuffer* CreateIndexBuffer( + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length) = 0; + +private: + std::unordered_map index_buffer_map_; +}; + + +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_BUFFER_CACHE_H_ diff --git a/src/xenia/gpu/d3d11/d3d11_buffer.cc b/src/xenia/gpu/d3d11/d3d11_buffer.cc new file mode 100644 index 000000000..98ea3ba9b --- /dev/null +++ b/src/xenia/gpu/d3d11/d3d11_buffer.cc @@ -0,0 +1,79 @@ +/** + ****************************************************************************** + * 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 + +#include +#include + + +using namespace xe; +using namespace xe::gpu; +using namespace xe::gpu::d3d11; +using namespace xe::gpu::xenos; + + +D3D11IndexBuffer::D3D11IndexBuffer( + D3D11BufferCache* buffer_cache, + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length) + : IndexBuffer(info, src_ptr, length), + buffer_cache_(buffer_cache), + handle_(nullptr) { +} + +D3D11IndexBuffer::~D3D11IndexBuffer() { + XESAFERELEASE(handle_); +} + +bool D3D11IndexBuffer::FetchNew(uint64_t hash) { + hash_ = hash; + + D3D11_BUFFER_DESC buffer_desc; + xe_zero_struct(&buffer_desc, sizeof(buffer_desc)); + buffer_desc.ByteWidth = info_.index_size; + buffer_desc.Usage = D3D11_USAGE_DYNAMIC; + buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; + buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + HRESULT hr = buffer_cache_->device()->CreateBuffer(&buffer_desc, NULL, &handle_); + if (FAILED(hr)) { + XELOGW("D3D11: failed to create index buffer"); + return false; + } + + return FetchDirty(hash); +} + +bool D3D11IndexBuffer::FetchDirty(uint64_t hash) { + hash_ = hash; + + // All that's done so far: + XEASSERT(info_.endianness == 0x2); + + D3D11_MAPPED_SUBRESOURCE res; + buffer_cache_->context()->Map(handle_, 0, D3D11_MAP_WRITE_DISCARD, 0, &res); + if (info_.index_32bit) { + const uint32_t* src = reinterpret_cast(src_); + uint32_t* dest = reinterpret_cast(res.pData); + for (uint32_t n = 0; n < info_.index_count; n++) { + uint32_t d = { XESWAP32(src[n]) }; + dest[n] = d; + } + } else { + const uint16_t* src = reinterpret_cast(src_); + uint16_t* dest = reinterpret_cast(res.pData); + for (uint32_t n = 0; n < info_.index_count; n++) { + uint16_t d = XESWAP16(src[n]); + dest[n] = d; + } + } + buffer_cache_->context()->Unmap(handle_, 0); + + return true; +} diff --git a/src/xenia/gpu/d3d11/d3d11_buffer.h b/src/xenia/gpu/d3d11/d3d11_buffer.h new file mode 100644 index 000000000..02160db2e --- /dev/null +++ b/src/xenia/gpu/d3d11/d3d11_buffer.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * 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_H_ +#define XENIA_GPU_D3D11_D3D11_BUFFER_H_ + +#include + +#include +#include + +#include + + +namespace xe { +namespace gpu { +namespace d3d11 { + +class D3D11BufferCache; + + +class D3D11IndexBuffer : public IndexBuffer { +public: + D3D11IndexBuffer(D3D11BufferCache* buffer_cache, + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length); + virtual ~D3D11IndexBuffer(); + + ID3D11Buffer* handle() const { return handle_; } + + bool FetchNew(uint64_t hash) override; + bool FetchDirty(uint64_t hash) override; + +private: + D3D11BufferCache* buffer_cache_; + ID3D11Buffer* handle_; +}; + + +class D3D11VertexBuffer : public VertexBuffer { +public: +private: +}; + + +} // namespace d3d11 +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_D3D11_D3D11_BUFFER_H_ diff --git a/src/xenia/gpu/d3d11/d3d11_buffer_cache.cc b/src/xenia/gpu/d3d11/d3d11_buffer_cache.cc new file mode 100644 index 000000000..b6aac9d1b --- /dev/null +++ b/src/xenia/gpu/d3d11/d3d11_buffer_cache.cc @@ -0,0 +1,38 @@ +/** + ****************************************************************************** + * 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 + +#include +#include + + +using namespace xe; +using namespace xe::gpu; +using namespace xe::gpu::d3d11; +using namespace xe::gpu::xenos; + + +D3D11BufferCache::D3D11BufferCache(ID3D11DeviceContext* context, + ID3D11Device* device) + : context_(context), device_(device) { + context->AddRef(); + device_->AddRef(); +} + +D3D11BufferCache::~D3D11BufferCache() { + XESAFERELEASE(device_); + XESAFERELEASE(context_); +} + +IndexBuffer* D3D11BufferCache::CreateIndexBuffer( + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length) { + return new D3D11IndexBuffer(this, info, src_ptr, length); +} diff --git a/src/xenia/gpu/d3d11/d3d11_buffer_cache.h b/src/xenia/gpu/d3d11/d3d11_buffer_cache.h new file mode 100644 index 000000000..eca2f5b55 --- /dev/null +++ b/src/xenia/gpu/d3d11/d3d11_buffer_cache.h @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * 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_CACHE_H_ +#define XENIA_GPU_D3D11_D3D11_BUFFER_CACHE_H_ + +#include + +#include +#include + +#include + + +namespace xe { +namespace gpu { +namespace d3d11 { + + +class D3D11BufferCache : public BufferCache { +public: + D3D11BufferCache(ID3D11DeviceContext* context, ID3D11Device* device); + virtual ~D3D11BufferCache(); + + ID3D11DeviceContext* context() const { return context_; } + ID3D11Device* device() const { return device_; } + +protected: + IndexBuffer* CreateIndexBuffer( + const IndexBufferInfo& info, + const uint8_t* src_ptr, size_t length) override; + +protected: + ID3D11DeviceContext* context_; + ID3D11Device* device_; +}; + + +} // namespace d3d11 +} // namespace gpu +} // namespace xe + + +#endif // XENIA_GPU_D3D11_D3D11_BUFFER_CACHE_H_ diff --git a/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc b/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc index f29afd285..209313091 100644 --- a/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc +++ b/src/xenia/gpu/d3d11/d3d11_graphics_driver.cc @@ -10,6 +10,8 @@ #include #include +#include +#include #include #include #include @@ -33,6 +35,7 @@ D3D11GraphicsDriver::D3D11GraphicsDriver( device_ = device; device_->AddRef(); device_->GetImmediateContext(&context_); + buffer_cache_ = new D3D11BufferCache(context_, device_); shader_cache_ = new D3D11ShaderCache(device_); texture_cache_ = new D3D11TextureCache(memory_, context_, device_); @@ -136,6 +139,7 @@ D3D11GraphicsDriver::~D3D11GraphicsDriver() { XESAFERELEASE(state_.constant_buffers.gs_consts); XESAFERELEASE(invalid_texture_view_); XESAFERELEASE(invalid_texture_sampler_state_); + delete buffer_cache_; delete texture_cache_; delete shader_cache_; XESAFERELEASE(context_); @@ -1098,43 +1102,20 @@ int D3D11GraphicsDriver::PrepareIndexBuffer( uint32_t address = index_base + address_translation_; - // All that's done so far: - XEASSERT(endianness == 0x2); - - ID3D11Buffer* buffer = 0; - D3D11_BUFFER_DESC buffer_desc; - xe_zero_struct(&buffer_desc, sizeof(buffer_desc)); - buffer_desc.ByteWidth = index_size; - buffer_desc.Usage = D3D11_USAGE_DYNAMIC; - buffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; - buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - device_->CreateBuffer(&buffer_desc, NULL, &buffer); - D3D11_MAPPED_SUBRESOURCE res; - context_->Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &res); - if (index_32bit) { - uint32_t* src = (uint32_t*)memory_->Translate(address); - uint32_t* dest = (uint32_t*)res.pData; - for (uint32_t n = 0; n < index_count; n++) { - uint32_t d = { XESWAP32(src[n]) }; - //XELOGGPU("i%.4d %0.8X", n, d); - dest[n] = d; - } - } else { - uint16_t* src = (uint16_t*)memory_->Translate(address); - uint16_t* dest = (uint16_t*)res.pData; - for (uint32_t n = 0; n < index_count; n++) { - uint16_t d = XESWAP16(src[n]); - //XELOGGPU("i%.4d, %.4X", n, d); - dest[n] = d; - } + IndexBufferInfo info; + info.endianness = endianness; + info.index_32bit = index_32bit; + info.index_count = index_count; + info.index_size = index_size; + auto ib = static_cast(buffer_cache_->FetchIndexBuffer( + info, memory_->Translate(address), index_size)); + if (!ib) { + return 1; } - context_->Unmap(buffer, 0); DXGI_FORMAT format; format = index_32bit ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; - context_->IASetIndexBuffer(buffer, format, 0); - - buffer->Release(); + context_->IASetIndexBuffer(ib->handle(), format, 0); return 0; } diff --git a/src/xenia/gpu/d3d11/d3d11_graphics_driver.h b/src/xenia/gpu/d3d11/d3d11_graphics_driver.h index 5a289d255..2f2316488 100644 --- a/src/xenia/gpu/d3d11/d3d11_graphics_driver.h +++ b/src/xenia/gpu/d3d11/d3d11_graphics_driver.h @@ -24,6 +24,7 @@ namespace xe { namespace gpu { namespace d3d11 { +class D3D11BufferCache; class D3D11PixelShader; class D3D11ShaderCache; class D3D11TextureCache; @@ -76,6 +77,7 @@ private: IDXGISwapChain* swap_chain_; ID3D11Device* device_; ID3D11DeviceContext* context_; + D3D11BufferCache* buffer_cache_; D3D11ShaderCache* shader_cache_; D3D11TextureCache* texture_cache_; diff --git a/src/xenia/gpu/d3d11/d3d11_shader_cache.h b/src/xenia/gpu/d3d11/d3d11_shader_cache.h index 661fb38f8..8c33523b4 100644 --- a/src/xenia/gpu/d3d11/d3d11_shader_cache.h +++ b/src/xenia/gpu/d3d11/d3d11_shader_cache.h @@ -28,10 +28,10 @@ public: virtual ~D3D11ShaderCache(); protected: - virtual Shader* CreateCore( + Shader* CreateCore( xenos::XE_GPU_SHADER_TYPE type, const uint8_t* src_ptr, size_t length, - uint64_t hash); + uint64_t hash) override; protected: ID3D11Device* device_; diff --git a/src/xenia/gpu/d3d11/sources.gypi b/src/xenia/gpu/d3d11/sources.gypi index 46c391ee6..6dc7ae242 100644 --- a/src/xenia/gpu/d3d11/sources.gypi +++ b/src/xenia/gpu/d3d11/sources.gypi @@ -1,6 +1,10 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'd3d11_buffer.cc', + 'd3d11_buffer.h', + 'd3d11_buffer_cache.cc', + 'd3d11_buffer_cache.h', 'd3d11_geometry_shader.cc', 'd3d11_geometry_shader.h', 'd3d11_gpu-private.h', diff --git a/src/xenia/gpu/shader_cache.cc b/src/xenia/gpu/shader_cache.cc index 33033bc36..2c5e84294 100644 --- a/src/xenia/gpu/shader_cache.cc +++ b/src/xenia/gpu/shader_cache.cc @@ -30,7 +30,7 @@ Shader* ShaderCache::Create( const uint8_t* src_ptr, size_t length) { uint64_t hash = Hash(src_ptr, length); Shader* shader = CreateCore(type, src_ptr, length, hash); - map_.insert(pair(hash, shader)); + map_.insert({ hash, shader }); return shader; } @@ -45,7 +45,7 @@ Shader* ShaderCache::Find( XE_GPU_SHADER_TYPE type, const uint8_t* src_ptr, size_t length) { uint64_t hash = Hash(src_ptr, length); - unordered_map::iterator it = map_.find(hash); + auto it = map_.find(hash); if (it != map_.end()) { return it->second; } @@ -58,19 +58,17 @@ Shader* ShaderCache::FindOrCreate( SCOPE_profile_cpu_f("gpu"); uint64_t hash = Hash(src_ptr, length); - unordered_map::iterator it = map_.find(hash); + auto it = map_.find(hash); if (it != map_.end()) { return it->second; } Shader* shader = CreateCore(type, src_ptr, length, hash); - map_.insert(pair(hash, shader)); + map_.insert({ hash, shader }); return shader; } void ShaderCache::Clear() { - // TODO(benvanik): clear. - for (unordered_map::iterator it = map_.begin(); - it != map_.end(); ++it) { + for (auto it = map_.begin(); it != map_.end(); ++it) { Shader* shader = it->second; delete shader; } diff --git a/src/xenia/gpu/sources.gypi b/src/xenia/gpu/sources.gypi index 9309e0ec3..b2c9134c0 100644 --- a/src/xenia/gpu/sources.gypi +++ b/src/xenia/gpu/sources.gypi @@ -1,6 +1,10 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'buffer.cc', + 'buffer.h', + 'buffer_cache.cc', + 'buffer_cache.h', 'command_buffer.h', 'gpu-private.h', 'gpu.cc',