Moving texture code into shared/separate files. Leaking a lot.

This commit is contained in:
Ben Vanik 2014-05-31 15:42:21 -07:00
parent e42460039f
commit 6607606b15
12 changed files with 961 additions and 546 deletions

View File

@ -13,6 +13,8 @@
#include <xenia/gpu/d3d11/d3d11_geometry_shader.h>
#include <xenia/gpu/d3d11/d3d11_shader.h>
#include <xenia/gpu/d3d11/d3d11_shader_cache.h>
#include <xenia/gpu/d3d11/d3d11_texture.h>
#include <xenia/gpu/d3d11/d3d11_texture_cache.h>
using namespace xe;
using namespace xe::gpu;
@ -32,6 +34,7 @@ D3D11GraphicsDriver::D3D11GraphicsDriver(
device_->AddRef();
device_->GetImmediateContext(&context_);
shader_cache_ = new D3D11ShaderCache(device_);
texture_cache_ = new D3D11TextureCache(memory_, context_, device_);
xe_zero_struct(&state_, sizeof(state_));
@ -126,9 +129,6 @@ D3D11GraphicsDriver::D3D11GraphicsDriver(
D3D11GraphicsDriver::~D3D11GraphicsDriver() {
RebuildRenderTargets(0, 0);
for (size_t n = 0; n < XECOUNT(state_.texture_fetchers); n++) {
XESAFERELEASE(state_.texture_fetchers[n].view);
}
XESAFERELEASE(state_.constant_buffers.float_constants);
XESAFERELEASE(state_.constant_buffers.bool_constants);
XESAFERELEASE(state_.constant_buffers.loop_constants);
@ -136,6 +136,7 @@ D3D11GraphicsDriver::~D3D11GraphicsDriver() {
XESAFERELEASE(state_.constant_buffers.gs_consts);
XESAFERELEASE(invalid_texture_view_);
XESAFERELEASE(invalid_texture_sampler_state_);
delete texture_cache_;
delete shader_cache_;
XESAFERELEASE(context_);
XESAFERELEASE(device_);
@ -1034,9 +1035,8 @@ int D3D11GraphicsDriver::PrepareTextureFetchers() {
for (int n = 0; n < XECOUNT(state_.texture_fetchers); n++) {
auto& fetcher = state_.texture_fetchers[n];
// TODO(benvanik): caching.
// TODO(benvanik): quick validate without refetching.
fetcher.enabled = false;
XESAFERELEASE(fetcher.view);
fetcher.view = NULL;
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + n * 6;
@ -1049,468 +1049,34 @@ int D3D11GraphicsDriver::PrepareTextureFetchers() {
// Stash a copy of the fetch register.
fetcher.fetch = fetch;
fetcher.info = GetTextureInfo(fetch);
if (fetcher.info.format == DXGI_FORMAT_UNKNOWN) {
// Fetch texture from the cache.
uint32_t address = (fetch.address << 12) + address_translation_;
auto texture_view = texture_cache_->FetchTexture(address, fetch);
if (!texture_view) {
XELOGW("D3D11: unable to fetch texture at %.8X", address);
continue;
}
if (texture_view->format == DXGI_FORMAT_UNKNOWN) {
XELOGW("D3D11: unknown texture format %d", fetch.format);
continue;
}
fetcher.view = static_cast<D3D11TextureView*>(texture_view);
D3D11_SHADER_RESOURCE_VIEW_DESC texture_view_desc;
xe_zero_struct(&texture_view_desc, sizeof(texture_view_desc));
// TODO(benvanik): this may need to be typed on the fetch instruction (float/int/etc?)
texture_view_desc.Format = fetcher.info.format;
ID3D11Resource* texture = NULL;
D3D_SRV_DIMENSION dimension = D3D11_SRV_DIMENSION_UNKNOWN;
switch (fetch.dimension) {
case DIMENSION_1D:
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
texture_view_desc.Texture1D.MipLevels = 1;
texture_view_desc.Texture1D.MostDetailedMip = 0;
if (FetchTexture1D(fetch, fetcher.info, &texture)) {
XELOGE("D3D11: failed to fetch Texture1D");
return 1;
}
break;
case DIMENSION_2D:
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
texture_view_desc.Texture2D.MipLevels = 1;
texture_view_desc.Texture2D.MostDetailedMip = 0;
if (FetchTexture2D(fetch, fetcher.info, &texture)) {
XELOGE("D3D11: failed to fetch Texture2D");
return 1;
}
break;
case DIMENSION_3D:
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
texture_view_desc.Texture3D.MipLevels = 1;
texture_view_desc.Texture3D.MostDetailedMip = 0;
if (FetchTexture3D(fetch, fetcher.info, &texture)) {
XELOGE("D3D11: failed to fetch Texture3D");
return 1;
}
break;
case DIMENSION_CUBE:
texture_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
texture_view_desc.TextureCube.MipLevels = 1;
texture_view_desc.TextureCube.MostDetailedMip = 0;
if (FetchTextureCube(fetch, fetcher.info, &texture)) {
XELOGE("D3D11: failed to fetch TextureCube");
return 1;
}
break;
}
XEASSERTNOTNULL(texture);
ID3D11ShaderResourceView* texture_view = NULL;
HRESULT hr = device_->CreateShaderResourceView(
texture, &texture_view_desc, &texture_view);
if (FAILED(hr)) {
XELOGE("D3D11: unable to create texture resource view");
texture->Release();
return 1;
}
texture->Release();
// Only enable if we get all the way down here successfully.
fetcher.enabled = true;
fetcher.view = texture_view;
}
return 0;
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/cc308051(v=vs.85).aspx
D3D11GraphicsDriver::TextureInfo D3D11GraphicsDriver::GetTextureInfo(
xe_gpu_texture_fetch_t& fetch) {
// a2xx_sq_surfaceformat
TextureInfo info;
info.format = DXGI_FORMAT_UNKNOWN;
info.block_size = 0;
info.texel_pitch = 0;
info.is_compressed = false;
switch (fetch.format) {
case FMT_8:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_RRR1:
info.format = DXGI_FORMAT_R8_UNORM;
break;
case XE_GPU_SWIZZLE_000R:
info.format = DXGI_FORMAT_A8_UNORM;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_8");
info.format = DXGI_FORMAT_A8_UNORM;
break;
}
info.block_size = 1;
info.texel_pitch = 1;
break;
case FMT_1_5_5_5:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_BGRA:
info.format = DXGI_FORMAT_B5G5R5A1_UNORM;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_1_5_5_5");
info.format = DXGI_FORMAT_B5G5R5A1_UNORM;
break;
}
info.block_size = 1;
info.texel_pitch = 2;
break;
case FMT_8_8_8_8:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_RGBA:
info.format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case XE_GPU_SWIZZLE_BGRA:
info.format = DXGI_FORMAT_B8G8R8A8_UNORM;
break;
case XE_GPU_SWIZZLE_RGB1:
info.format = DXGI_FORMAT_R8G8B8A8_UNORM; // ?
break;
case XE_GPU_SWIZZLE_BGR1:
info.format = DXGI_FORMAT_B8G8R8X8_UNORM;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_8_8_8_8");
info.format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
}
info.block_size = 1;
info.texel_pitch = 4;
break;
case FMT_4_4_4_4:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_BGRA:
info.format = DXGI_FORMAT_B4G4R4A4_UNORM; // only supported on Windows 8+
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_4_4_4_4");
info.format = DXGI_FORMAT_B4G4R4A4_UNORM; // only supported on Windows 8+
break;
}
info.block_size = 1;
info.texel_pitch = 2;
break;
case FMT_16_16_16_16_FLOAT:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_RGBA:
info.format = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_16_16_16_16_FLOAT");
info.format = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
}
info.block_size = 1;
info.texel_pitch = 8;
break;
case FMT_32_FLOAT:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_R111:
info.format = DXGI_FORMAT_R32_FLOAT;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_32_FLOAT");
info.format = DXGI_FORMAT_R32_FLOAT;
break;
}
info.block_size = 1;
info.texel_pitch = 4;
break;
case FMT_DXT1:
info.format = DXGI_FORMAT_BC1_UNORM;
info.block_size = 4;
info.texel_pitch = 8;
info.is_compressed = true;
break;
case FMT_DXT2_3:
case FMT_DXT4_5:
info.format = (fetch.format == FMT_DXT4_5 ? DXGI_FORMAT_BC3_UNORM : DXGI_FORMAT_BC2_UNORM);
info.block_size = 4;
info.texel_pitch = 16;
info.is_compressed = true;
break;
case FMT_1_REVERSE:
case FMT_1:
case FMT_5_6_5:
case FMT_6_5_5:
case FMT_2_10_10_10:
case FMT_8_A:
case FMT_8_B:
case FMT_8_8:
case FMT_Cr_Y1_Cb_Y0:
case FMT_Y1_Cr_Y0_Cb:
case FMT_5_5_5_1:
case FMT_8_8_8_8_A:
case FMT_10_11_11:
case FMT_11_11_10:
case FMT_24_8:
case FMT_24_8_FLOAT:
case FMT_16:
case FMT_16_16:
case FMT_16_16_16_16:
case FMT_16_EXPAND:
case FMT_16_16_EXPAND:
case FMT_16_16_16_16_EXPAND:
case FMT_16_FLOAT:
case FMT_16_16_FLOAT:
case FMT_32:
case FMT_32_32:
case FMT_32_32_32_32:
case FMT_32_32_FLOAT:
case FMT_32_32_32_32_FLOAT:
case FMT_32_AS_8:
case FMT_32_AS_8_8:
case FMT_16_MPEG:
case FMT_16_16_MPEG:
case FMT_8_INTERLACED:
case FMT_32_AS_8_INTERLACED:
case FMT_32_AS_8_8_INTERLACED:
case FMT_16_INTERLACED:
case FMT_16_MPEG_INTERLACED:
case FMT_16_16_MPEG_INTERLACED:
case FMT_DXN:
case FMT_8_8_8_8_AS_16_16_16_16:
case FMT_DXT1_AS_16_16_16_16:
case FMT_DXT2_3_AS_16_16_16_16:
case FMT_DXT4_5_AS_16_16_16_16:
case FMT_2_10_10_10_AS_16_16_16_16:
case FMT_10_11_11_AS_16_16_16_16:
case FMT_11_11_10_AS_16_16_16_16:
case FMT_32_32_32_FLOAT:
case FMT_DXT3A:
case FMT_DXT5A:
case FMT_CTX1:
case FMT_DXT3A_AS_1_1_1_1:
info.format = DXGI_FORMAT_UNKNOWN;
break;
}
return info;
}
int D3D11GraphicsDriver::FetchTexture1D(
xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture) {
SCOPE_profile_cpu_f("gpu");
uint32_t address = (fetch.address << 12) + address_translation_;
uint32_t width = 1 + fetch.size_1d.width;
D3D11_TEXTURE1D_DESC texture_desc;
xe_zero_struct(&texture_desc, sizeof(texture_desc));
texture_desc.Width = width;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = info.format;
texture_desc.Usage = D3D11_USAGE_DYNAMIC;
texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
texture_desc.MiscFlags = 0; // D3D11_RESOURCE_MISC_GENERATE_MIPS?
HRESULT hr = device_->CreateTexture1D(
&texture_desc, NULL, (ID3D11Texture1D**)out_texture);
if (FAILED(hr)) {
return 1;
}
return 0;
}
XEFORCEINLINE void TextureSwap(uint8_t* dest, const uint8_t* src, uint32_t pitch, XE_GPU_ENDIAN endianness) {
switch (endianness) {
case XE_GPU_ENDIAN_8IN16:
for (uint32_t i = 0; i < pitch; i += 2, src += 2, dest += 2) {
*(uint16_t*)dest = XESWAP16(*(uint16_t*)src);
}
break;
case XE_GPU_ENDIAN_8IN32: // Swap bytes.
for (uint32_t i = 0; i < pitch; i += 4, src += 4, dest += 4) {
*(uint32_t*)dest = XESWAP32(*(uint32_t*)src);
}
break;
case XE_GPU_ENDIAN_16IN32: // Swap half words.
for (uint32_t i = 0; i < pitch; i += 4, src += 4, dest += 4) {
uint32_t value = *(uint32_t*)src;
*(uint32_t*)dest = ((value >> 16) & 0xFFFF) | (value << 16);
}
break;
default:
case XE_GPU_ENDIAN_NONE:
memcpy(dest, src, pitch);
break;
}
}
// https://code.google.com/p/crunch/source/browse/trunk/inc/crn_decomp.h#4104
XEFORCEINLINE uint32_t TiledOffset2DOuter(uint32_t y, uint32_t width, uint32_t log_bpp)
{
uint32_t macro = ((y >> 5) * (width >> 5)) << (log_bpp + 7);
uint32_t micro = ((y & 6) << 2) << log_bpp;
return macro + ((micro & ~15) << 1) + (micro & 15) + ((y & 8) << (3 + log_bpp)) + ((y & 1) << 4);
}
XEFORCEINLINE uint32_t TiledOffset2DInner(uint32_t x, uint32_t y, uint32_t bpp, uint32_t base_offset)
{
uint32_t macro = (x >> 5) << (bpp + 7);
uint32_t micro = (x & 7) << bpp;
uint32_t offset = base_offset + (macro + ((micro & ~15) << 1) + (micro & 15));
return ((offset & ~511) << 3) + ((offset & 448) << 2) + (offset & 63) +
((y & 16) << 7) + (((((y & 8) >> 2) + (x >> 3)) & 3) << 6);
}
int D3D11GraphicsDriver::FetchTexture2D(
xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture) {
SCOPE_profile_cpu_f("gpu");
XEASSERTTRUE(fetch.dimension == 1);
uint32_t address = (fetch.address << 12) + address_translation_;
uint32_t logical_width = 1 + fetch.size_2d.width;
uint32_t logical_height = 1 + fetch.size_2d.height;
uint32_t block_width = logical_width / info.block_size;
uint32_t block_height = logical_height / info.block_size;
uint32_t input_width, input_height;
uint32_t output_width, output_height;
if (!info.is_compressed) {
// must be 32x32, but also must have a pitch that is a multiple of 256 bytes
uint32_t bytes_per_block = info.block_size * info.block_size * info.texel_pitch;
uint32_t width_multiple = 32;
if (bytes_per_block) {
uint32_t minimum_multiple = 256 / bytes_per_block;
if (width_multiple < minimum_multiple) {
width_multiple = minimum_multiple;
}
}
input_width = XEROUNDUP(logical_width, width_multiple);
input_height = XEROUNDUP(logical_height, 32);
output_width = logical_width;
output_height = logical_height;
}
else {
// must be 128x128
input_width = XEROUNDUP(logical_width, 128);
input_height = XEROUNDUP(logical_height, 128);
output_width = XENEXTPOW2(logical_width);
output_height = XENEXTPOW2(logical_height);
}
D3D11_TEXTURE2D_DESC texture_desc;
xe_zero_struct(&texture_desc, sizeof(texture_desc));
texture_desc.Width = output_width;
texture_desc.Height = 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 = device_->CreateTexture2D(
&texture_desc, NULL, (ID3D11Texture2D**)out_texture);
if (FAILED(hr)) {
return 1;
}
// TODO(benvanik): all mip levels.
D3D11_MAPPED_SUBRESOURCE res;
hr = context_->Map(*out_texture, 0,
D3D11_MAP_WRITE_DISCARD, 0, &res);
if (FAILED(hr)) {
XELOGE("D3D11: failed to map texture");
return 1;
}
auto logical_pitch = (logical_width / info.block_size) * info.texel_pitch;
auto input_pitch = (input_width / info.block_size) * info.texel_pitch;
auto output_pitch = res.RowPitch; // (output_width / info.block_size) * info.texel_pitch;
const uint8_t* src = memory_->Translate(address);
uint8_t* dest = (uint8_t*)res.pData;
memset(dest, 0, output_pitch * (output_height / info.block_size)); // TODO(gibbed): remove me later
if (!fetch.tiled) {
dest = (uint8_t*)res.pData;
for (uint32_t y = 0; y < block_height; y++) {
for (uint32_t x = 0; x < logical_pitch; x += info.texel_pitch) {
TextureSwap(dest + x, src + x, info.texel_pitch, (XE_GPU_ENDIAN)fetch.endianness);
}
src += 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 < block_height; y++, output_base_offset += output_pitch) {
auto input_base_offset = TiledOffset2DOuter(y, (input_width / info.block_size), bpp);
for (uint32_t x = 0, output_offset = output_base_offset; x < 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, (XE_GPU_ENDIAN)fetch.endianness);
}
}
}
context_->Unmap(*out_texture, 0);
return 0;
}
int D3D11GraphicsDriver::FetchTexture3D(
xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture) {
SCOPE_profile_cpu_f("gpu");
XELOGE("D3D11: FetchTexture2D not yet implemented");
XEASSERTALWAYS();
return 1;
//D3D11_TEXTURE3D_DESC texture_desc;
//xe_zero_struct(&texture_desc, sizeof(texture_desc));
//texture_desc.Width;
//texture_desc.Height;
//texture_desc.Depth;
//texture_desc.MipLevels;
//texture_desc.Format;
//texture_desc.Usage;
//texture_desc.BindFlags;
//texture_desc.CPUAccessFlags;
//texture_desc.MiscFlags;
//hr = device_->CreateTexture3D(
// &texture_desc, &initial_data, (ID3D11Texture3D**)&texture);
}
int D3D11GraphicsDriver::FetchTextureCube(
xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture) {
SCOPE_profile_cpu_f("gpu");
XELOGE("D3D11: FetchTextureCube not yet implemented");
XEASSERTALWAYS();
return 1;
}
int D3D11GraphicsDriver::PrepareTextureSampler(
xenos::XE_GPU_SHADER_TYPE shader_type, Shader::tex_buffer_desc_t& desc) {
SCOPE_profile_cpu_f("gpu");
// If the fetcher is disabled or invalid, set some default textures.
auto& fetcher = state_.texture_fetchers[desc.fetch_slot];
auto& info = fetcher.info;
if (!fetcher.enabled ||
info.format == DXGI_FORMAT_UNKNOWN) {
fetcher.view->format == DXGI_FORMAT_UNKNOWN) {
XELOGW("D3D11: ignoring texture fetch: disabled or an unknown format");
if (shader_type == XE_GPU_SHADER_TYPE_VERTEX) {
context_->VSSetShaderResources(desc.input_index,
@ -1526,82 +1092,16 @@ int D3D11GraphicsDriver::PrepareTextureSampler(
return 0;
}
HRESULT hr;
// Get and set the real shader resource views/samplers.
if (shader_type == XE_GPU_SHADER_TYPE_VERTEX) {
context_->VSSetShaderResources(desc.input_index, 1, &fetcher.view);
context_->VSSetShaderResources(desc.input_index, 1, &fetcher.view->srv);
} else {
context_->PSSetShaderResources(desc.input_index, 1, &fetcher.view);
context_->PSSetShaderResources(desc.input_index, 1, &fetcher.view->srv);
}
D3D11_SAMPLER_DESC sampler_desc;
xe_zero_struct(&sampler_desc, sizeof(sampler_desc));
uint32_t min_filter = desc.tex_fetch.min_filter == 3 ?
fetcher.fetch.min_filter : desc.tex_fetch.min_filter;
uint32_t mag_filter = desc.tex_fetch.mag_filter == 3 ?
fetcher.fetch.mag_filter : desc.tex_fetch.mag_filter;
uint32_t mip_filter = desc.tex_fetch.mip_filter == 3 ?
fetcher.fetch.mip_filter : desc.tex_fetch.mip_filter;
// 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[min_filter][mag_filter][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[fetcher.fetch.clamp_x];
sampler_desc.AddressV = mode_map[fetcher.fetch.clamp_y];
sampler_desc.AddressW = mode_map[fetcher.fetch.clamp_z];
sampler_desc.MipLODBias;
sampler_desc.MaxAnisotropy = 1;
sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
sampler_desc.BorderColor[0];
sampler_desc.BorderColor[1];
sampler_desc.BorderColor[2];
sampler_desc.BorderColor[3];
sampler_desc.MinLOD;
sampler_desc.MaxLOD;
ID3D11SamplerState* sampler_state = NULL;
hr = device_->CreateSamplerState(&sampler_desc, &sampler_state);
if (FAILED(hr)) {
XELOGE("D3D11: unable to create sampler state");
ID3D11SamplerState* sampler_state = texture_cache_->GetSamplerState(
fetcher.fetch, desc);
if (!sampler_state) {
XELOGW("D3D11: failed to set sampler state; ignoring texture");
return 1;
}
if (shader_type == XE_GPU_SHADER_TYPE_VERTEX) {
@ -1609,7 +1109,7 @@ int D3D11GraphicsDriver::PrepareTextureSampler(
} else {
context_->PSSetSamplers(desc.input_index, 1, &sampler_state);
}
sampler_state->Release();
XESAFERELEASE(sampler_state);
return 0;
}

View File

@ -26,6 +26,8 @@ namespace d3d11 {
class D3D11PixelShader;
class D3D11ShaderCache;
class D3D11TextureCache;
struct D3D11TextureView;
class D3D11VertexShader;
@ -66,25 +68,6 @@ private:
int PrepareTextureFetchers();
int PrepareTextureSampler(xenos::XE_GPU_SHADER_TYPE shader_type,
Shader::tex_buffer_desc_t& desc);
typedef struct {
DXGI_FORMAT format;
uint32_t block_size;
uint32_t texel_pitch;
bool is_compressed;
} TextureInfo;
TextureInfo GetTextureInfo(xenos::xe_gpu_texture_fetch_t& fetch);
int FetchTexture1D(xenos::xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture);
int FetchTexture2D(xenos::xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture);
int FetchTexture3D(xenos::xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture);
int FetchTextureCube(xenos::xe_gpu_texture_fetch_t& fetch,
TextureInfo& info,
ID3D11Resource** out_texture);
int PrepareIndexBuffer(
bool index_32bit, uint32_t index_count,
uint32_t index_base, uint32_t index_size, uint32_t endianness);
@ -94,6 +77,7 @@ private:
ID3D11Device* device_;
ID3D11DeviceContext* context_;
D3D11ShaderCache* shader_cache_;
D3D11TextureCache* texture_cache_;
ID3D11ShaderResourceView* invalid_texture_view_;
ID3D11SamplerState* invalid_texture_sampler_state_;
@ -125,8 +109,7 @@ private:
struct {
bool enabled;
xenos::xe_gpu_texture_fetch_t fetch;
TextureInfo info;
ID3D11ShaderResourceView* view;
D3D11TextureView* view;
} texture_fetchers[32];
} state_;

View File

@ -0,0 +1,255 @@
/**
******************************************************************************
* 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.h>
#include <xenia/gpu/gpu-private.h>
#include <xenia/gpu/d3d11/d3d11_texture_cache.h>
#include <xenia/gpu/xenos/ucode.h>
#include <xenia/gpu/xenos/xenos.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
using namespace xe::gpu::xenos;
D3D11Texture::D3D11Texture(D3D11TextureCache* cache, uint32_t address)
: Texture(address),
cache_(cache) {
}
D3D11Texture::~D3D11Texture() {
// views
}
TextureView* D3D11Texture::Fetch(
const xenos::xe_gpu_texture_fetch_t& fetch) {
D3D11TextureView* view = new D3D11TextureView();
view->texture = this;
if (!FillViewInfo(view, fetch)) {
return nullptr;
}
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
xe_zero_struct(&srv_desc, sizeof(srv_desc));
// TODO(benvanik): this may need to be typed on the fetch instruction (float/int/etc?)
srv_desc.Format = view->format;
D3D_SRV_DIMENSION dimension = D3D11_SRV_DIMENSION_UNKNOWN;
switch (view->dimensions) {
case DIMENSION_1D:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
srv_desc.Texture1D.MipLevels = 1;
srv_desc.Texture1D.MostDetailedMip = 0;
if (!FetchTexture1D(view, fetch)) {
XELOGE("D3D11: failed to fetch Texture1D");
return nullptr;
}
break;
case DIMENSION_2D:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srv_desc.Texture2D.MipLevels = 1;
srv_desc.Texture2D.MostDetailedMip = 0;
if (!FetchTexture2D(view, fetch)) {
XELOGE("D3D11: failed to fetch Texture2D");
return nullptr;
}
break;
case DIMENSION_3D:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
srv_desc.Texture3D.MipLevels = 1;
srv_desc.Texture3D.MostDetailedMip = 0;
if (!FetchTexture3D(view, fetch)) {
XELOGE("D3D11: failed to fetch Texture3D");
return nullptr;
}
break;
case DIMENSION_CUBE:
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
srv_desc.TextureCube.MipLevels = 1;
srv_desc.TextureCube.MostDetailedMip = 0;
if (!FetchTextureCube(view, fetch)) {
XELOGE("D3D11: failed to fetch TextureCube");
return nullptr;
}
break;
}
HRESULT hr = cache_->device()->CreateShaderResourceView(
view->resource, &srv_desc, &view->srv);
if (FAILED(hr)) {
XELOGE("D3D11: unable to create texture resource view");
return nullptr;
}
return view;
}
bool D3D11Texture::FetchTexture1D(
D3D11TextureView* view, const xe_gpu_texture_fetch_t& fetch) {
SCOPE_profile_cpu_f("gpu");
uint32_t width = 1 + fetch.size_1d.width;
D3D11_TEXTURE1D_DESC texture_desc;
xe_zero_struct(&texture_desc, sizeof(texture_desc));
texture_desc.Width = width;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = view->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 = cache_->device()->CreateTexture1D(
&texture_desc, NULL, (ID3D11Texture1D**)&view->resource);
if (FAILED(hr)) {
return false;
}
// TODO(benvanik): upload!
XELOGE("D3D11: FetchTexture1D not yet implemented");
return false;
}
bool D3D11Texture::FetchTexture2D(
D3D11TextureView* view, const xe_gpu_texture_fetch_t& fetch) {
SCOPE_profile_cpu_f("gpu");
XEASSERTTRUE(fetch.dimension == 1);
uint32_t logical_width = 1 + fetch.size_2d.width;
uint32_t logical_height = 1 + fetch.size_2d.height;
uint32_t block_width = logical_width / view->block_size;
uint32_t block_height = logical_height / view->block_size;
uint32_t input_width, input_height;
uint32_t output_width, output_height;
if (!view->is_compressed) {
// must be 32x32, but also must have a pitch that is a multiple of 256 bytes
uint32_t bytes_per_block = view->block_size * view->block_size *
view->texel_pitch;
uint32_t width_multiple = 32;
if (bytes_per_block) {
uint32_t minimum_multiple = 256 / bytes_per_block;
if (width_multiple < minimum_multiple) {
width_multiple = minimum_multiple;
}
}
input_width = XEROUNDUP(logical_width, width_multiple);
input_height = XEROUNDUP(logical_height, 32);
output_width = logical_width;
output_height = logical_height;
}
else {
// must be 128x128
input_width = XEROUNDUP(logical_width, 128);
input_height = XEROUNDUP(logical_height, 128);
output_width = XENEXTPOW2(logical_width);
output_height = XENEXTPOW2(logical_height);
}
D3D11_TEXTURE2D_DESC texture_desc;
xe_zero_struct(&texture_desc, sizeof(texture_desc));
texture_desc.Width = output_width;
texture_desc.Height = output_height;
texture_desc.MipLevels = 1;
texture_desc.ArraySize = 1;
texture_desc.Format = view->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 = cache_->device()->CreateTexture2D(
&texture_desc, NULL, (ID3D11Texture2D**)&view->resource);
if (FAILED(hr)) {
return false;
}
// TODO(benvanik): all mip levels.
D3D11_MAPPED_SUBRESOURCE res;
hr = cache_->context()->Map(view->resource, 0,
D3D11_MAP_WRITE_DISCARD, 0, &res);
if (FAILED(hr)) {
XELOGE("D3D11: failed to map texture");
return false;
}
auto logical_pitch = (logical_width / view->block_size) * view->texel_pitch;
auto input_pitch = (input_width / view->block_size) * view->texel_pitch;
auto output_pitch = res.RowPitch; // (output_width / info.block_size) * info.texel_pitch;
const uint8_t* src = cache_->memory()->Translate(address_);
uint8_t* dest = (uint8_t*)res.pData;
//memset(dest, 0, output_pitch * (output_height / view->block_size)); // TODO(gibbed): remove me later
if (!fetch.tiled) {
dest = (uint8_t*)res.pData;
for (uint32_t y = 0; y < block_height; y++) {
for (uint32_t x = 0; x < logical_pitch; x += view->texel_pitch) {
TextureSwap(dest + x, src + x, view->texel_pitch, (XE_GPU_ENDIAN)fetch.endianness);
}
src += input_pitch;
dest += output_pitch;
}
}
else {
auto bpp = (view->texel_pitch >> 2) + ((view->texel_pitch >> 1) >> (view->texel_pitch >> 2));
for (uint32_t y = 0, output_base_offset = 0; y < block_height; y++, output_base_offset += output_pitch) {
auto input_base_offset = TiledOffset2DOuter(y, (input_width / view->block_size), bpp);
for (uint32_t x = 0, output_offset = output_base_offset; x < block_width; x++, output_offset += view->texel_pitch) {
auto input_offset = TiledOffset2DInner(x, y, bpp, input_base_offset) >> bpp;
TextureSwap(dest + output_offset,
src + input_offset * view->texel_pitch,
view->texel_pitch, (XE_GPU_ENDIAN)fetch.endianness);
}
}
}
cache_->context()->Unmap(view->resource, 0);
return true;
}
bool D3D11Texture::FetchTexture3D(
D3D11TextureView* view, const xe_gpu_texture_fetch_t& fetch) {
SCOPE_profile_cpu_f("gpu");
XELOGE("D3D11: FetchTexture3D not yet implemented");
XEASSERTALWAYS();
return false;
//D3D11_TEXTURE3D_DESC texture_desc;
//xe_zero_struct(&texture_desc, sizeof(texture_desc));
//texture_desc.Width;
//texture_desc.Height;
//texture_desc.Depth;
//texture_desc.MipLevels;
//texture_desc.Format;
//texture_desc.Usage;
//texture_desc.BindFlags;
//texture_desc.CPUAccessFlags;
//texture_desc.MiscFlags;
//hr = device_->CreateTexture3D(
// &texture_desc, &initial_data, (ID3D11Texture3D**)&view->resource);
}
bool D3D11Texture::FetchTextureCube(
D3D11TextureView* view, const xe_gpu_texture_fetch_t& fetch) {
SCOPE_profile_cpu_f("gpu");
XELOGE("D3D11: FetchTextureCube not yet implemented");
XEASSERTALWAYS();
return false;
}

View File

@ -0,0 +1,69 @@
/**
******************************************************************************
* 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_H_
#define XENIA_GPU_D3D11_D3D11_TEXTURE_H_
#include <xenia/core.h>
#include <xenia/gpu/texture.h>
#include <d3d11.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11TextureCache;
struct D3D11TextureView : TextureView {
ID3D11Resource* resource;
ID3D11ShaderResourceView* srv;
D3D11TextureView()
: resource(nullptr), srv(nullptr) {}
virtual ~D3D11TextureView() {
XESAFERELEASE(srv);
XESAFERELEASE(resource);
}
};
class D3D11Texture : public Texture {
public:
D3D11Texture(D3D11TextureCache* cache, uint32_t address);
virtual ~D3D11Texture();
TextureView* Fetch(
const xenos::xe_gpu_texture_fetch_t& fetch) override;
protected:
bool FetchTexture1D(
D3D11TextureView* view, const xenos::xe_gpu_texture_fetch_t& fetch);
bool FetchTexture2D(
D3D11TextureView* view, const xenos::xe_gpu_texture_fetch_t& fetch);
bool FetchTexture3D(
D3D11TextureView* view, const xenos::xe_gpu_texture_fetch_t& fetch);
bool FetchTextureCube(
D3D11TextureView* view, const xenos::xe_gpu_texture_fetch_t& fetch);
D3D11TextureCache* cache_;
// views
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_TEXTURE_H_

View File

@ -0,0 +1,113 @@
/**
******************************************************************************
* 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_cache.h>
#include <xenia/gpu/gpu-private.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::d3d11;
D3D11TextureCache::D3D11TextureCache(
Memory* memory,
ID3D11DeviceContext* context, ID3D11Device* device)
: TextureCache(memory),
context_(context), device_(device) {
context_->AddRef();
device_->AddRef();
}
D3D11TextureCache::~D3D11TextureCache() {
XESAFERELEASE(device_);
XESAFERELEASE(context_);
}
Texture* D3D11TextureCache::CreateTexture(
uint32_t address, const xenos::xe_gpu_texture_fetch_t& fetch) {
return new D3D11Texture(this, address);
}
ID3D11SamplerState* D3D11TextureCache::GetSamplerState(
const xenos::xe_gpu_texture_fetch_t& fetch,
const Shader::tex_buffer_desc_t& desc) {
D3D11_SAMPLER_DESC sampler_desc;
xe_zero_struct(&sampler_desc, sizeof(sampler_desc));
uint32_t min_filter = desc.tex_fetch.min_filter == 3 ?
fetch.min_filter : desc.tex_fetch.min_filter;
uint32_t mag_filter = desc.tex_fetch.mag_filter == 3 ?
fetch.mag_filter : desc.tex_fetch.mag_filter;
uint32_t mip_filter = desc.tex_fetch.mip_filter == 3 ?
fetch.mip_filter : desc.tex_fetch.mip_filter;
// 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[min_filter][mag_filter][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[fetch.clamp_x];
sampler_desc.AddressV = mode_map[fetch.clamp_y];
sampler_desc.AddressW = mode_map[fetch.clamp_z];
sampler_desc.MipLODBias;
sampler_desc.MaxAnisotropy = 1;
sampler_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
sampler_desc.BorderColor[0];
sampler_desc.BorderColor[1];
sampler_desc.BorderColor[2];
sampler_desc.BorderColor[3];
sampler_desc.MinLOD;
sampler_desc.MaxLOD;
ID3D11SamplerState* sampler_state = NULL;
HRESULT hr = device_->CreateSamplerState(&sampler_desc, &sampler_state);
if (FAILED(hr)) {
XELOGE("D3D11: unable to create sampler state");
return nullptr;
}
return sampler_state;
}

View File

@ -0,0 +1,55 @@
/**
******************************************************************************
* 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_CACHE_H_
#define XENIA_GPU_D3D11_D3D11_TEXTURE_CACHE_H_
#include <xenia/core.h>
#include <xenia/gpu/texture_cache.h>
#include <xenia/gpu/shader.h>
#include <xenia/gpu/d3d11/d3d11_texture.h>
#include <d3d11.h>
namespace xe {
namespace gpu {
namespace d3d11 {
class D3D11TextureCache : public TextureCache {
public:
D3D11TextureCache(Memory* memory,
ID3D11DeviceContext* context, ID3D11Device* device);
virtual ~D3D11TextureCache();
ID3D11DeviceContext* context() const { return context_; }
ID3D11Device* device() const { return device_; }
ID3D11SamplerState* GetSamplerState(
const xenos::xe_gpu_texture_fetch_t& fetch,
const Shader::tex_buffer_desc_t& desc);
protected:
Texture* CreateTexture(uint32_t address,
const xenos::xe_gpu_texture_fetch_t& fetch) override;
private:
ID3D11DeviceContext* context_;
ID3D11Device* device_;
};
} // namespace d3d11
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_D3D11_D3D11_TEXTURE_CACHE_H_

View File

@ -16,6 +16,10 @@
'd3d11_shader.h',
'd3d11_shader_cache.cc',
'd3d11_shader_cache.h',
'd3d11_texture.cc',
'd3d11_texture.h',
'd3d11_texture_cache.cc',
'd3d11_texture_cache.h',
'd3d11_window.cc',
'd3d11_window.h',
],

View File

@ -15,6 +15,10 @@
'shader.h',
'shader_cache.cc',
'shader_cache.h',
'texture.cc',
'texture.h',
'texture_cache.cc',
'texture_cache.h',
],
'includes': [

264
src/xenia/gpu/texture.cc Normal file
View File

@ -0,0 +1,264 @@
/**
******************************************************************************
* 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/texture.h>
#include <xenia/gpu/xenos/ucode.h>
#include <xenia/gpu/xenos/xenos.h>
// TODO(benvanik): replace DXGI constants with xenia constants.
#include <d3d11.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::xenos;
Texture::Texture(uint32_t address)
: address_(address) {
}
bool Texture::FillViewInfo(TextureView* view,
const xenos::xe_gpu_texture_fetch_t& fetch) {
// http://msdn.microsoft.com/en-us/library/windows/desktop/cc308051(v=vs.85).aspx
// a2xx_sq_surfaceformat
view->dimensions = fetch.dimension;
switch (fetch.dimension) {
case DIMENSION_1D:
view->width = fetch.size_1d.width;
break;
case DIMENSION_2D:
view->width = fetch.size_2d.width;
view->height = fetch.size_2d.height;
break;
case DIMENSION_3D:
view->width = fetch.size_3d.width;
view->height = fetch.size_3d.height;
view->depth = fetch.size_3d.depth;
break;
case DIMENSION_CUBE:
view->width = fetch.size_stack.width;
view->height = fetch.size_stack.height;
view->depth = fetch.size_stack.depth;
break;
}
view->format = DXGI_FORMAT_UNKNOWN;
view->block_size = 0;
view->texel_pitch = 0;
view->is_compressed = false;
switch (fetch.format) {
case FMT_8:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_RRR1:
view->format = DXGI_FORMAT_R8_UNORM;
break;
case XE_GPU_SWIZZLE_000R:
view->format = DXGI_FORMAT_A8_UNORM;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_8");
view->format = DXGI_FORMAT_A8_UNORM;
break;
}
view->block_size = 1;
view->texel_pitch = 1;
break;
case FMT_1_5_5_5:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_BGRA:
view->format = DXGI_FORMAT_B5G5R5A1_UNORM;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_1_5_5_5");
view->format = DXGI_FORMAT_B5G5R5A1_UNORM;
break;
}
view->block_size = 1;
view->texel_pitch = 2;
break;
case FMT_8_8_8_8:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_RGBA:
view->format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case XE_GPU_SWIZZLE_BGRA:
view->format = DXGI_FORMAT_B8G8R8A8_UNORM;
break;
case XE_GPU_SWIZZLE_RGB1:
view->format = DXGI_FORMAT_R8G8B8A8_UNORM; // ?
break;
case XE_GPU_SWIZZLE_BGR1:
view->format = DXGI_FORMAT_B8G8R8X8_UNORM;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_8_8_8_8");
view->format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
}
view->block_size = 1;
view->texel_pitch = 4;
break;
case FMT_4_4_4_4:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_BGRA:
view->format = DXGI_FORMAT_B4G4R4A4_UNORM; // only supported on Windows 8+
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_4_4_4_4");
view->format = DXGI_FORMAT_B4G4R4A4_UNORM; // only supported on Windows 8+
break;
}
view->block_size = 1;
view->texel_pitch = 2;
break;
case FMT_16_16_16_16_FLOAT:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_RGBA:
view->format = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_16_16_16_16_FLOAT");
view->format = DXGI_FORMAT_R16G16B16A16_FLOAT;
break;
}
view->block_size = 1;
view->texel_pitch = 8;
break;
case FMT_32_FLOAT:
switch (fetch.swizzle) {
case XE_GPU_SWIZZLE_R111:
view->format = DXGI_FORMAT_R32_FLOAT;
break;
default:
XELOGW("D3D11: unhandled swizzle for FMT_32_FLOAT");
view->format = DXGI_FORMAT_R32_FLOAT;
break;
}
view->block_size = 1;
view->texel_pitch = 4;
break;
case FMT_DXT1:
view->format = DXGI_FORMAT_BC1_UNORM;
view->block_size = 4;
view->texel_pitch = 8;
view->is_compressed = true;
break;
case FMT_DXT2_3:
case FMT_DXT4_5:
view->format = (fetch.format == FMT_DXT4_5 ? DXGI_FORMAT_BC3_UNORM : DXGI_FORMAT_BC2_UNORM);
view->block_size = 4;
view->texel_pitch = 16;
view->is_compressed = true;
break;
case FMT_1_REVERSE:
case FMT_1:
case FMT_5_6_5:
case FMT_6_5_5:
case FMT_2_10_10_10:
case FMT_8_A:
case FMT_8_B:
case FMT_8_8:
case FMT_Cr_Y1_Cb_Y0:
case FMT_Y1_Cr_Y0_Cb:
case FMT_5_5_5_1:
case FMT_8_8_8_8_A:
case FMT_10_11_11:
case FMT_11_11_10:
case FMT_24_8:
case FMT_24_8_FLOAT:
case FMT_16:
case FMT_16_16:
case FMT_16_16_16_16:
case FMT_16_EXPAND:
case FMT_16_16_EXPAND:
case FMT_16_16_16_16_EXPAND:
case FMT_16_FLOAT:
case FMT_16_16_FLOAT:
case FMT_32:
case FMT_32_32:
case FMT_32_32_32_32:
case FMT_32_32_FLOAT:
case FMT_32_32_32_32_FLOAT:
case FMT_32_AS_8:
case FMT_32_AS_8_8:
case FMT_16_MPEG:
case FMT_16_16_MPEG:
case FMT_8_INTERLACED:
case FMT_32_AS_8_INTERLACED:
case FMT_32_AS_8_8_INTERLACED:
case FMT_16_INTERLACED:
case FMT_16_MPEG_INTERLACED:
case FMT_16_16_MPEG_INTERLACED:
case FMT_DXN:
case FMT_8_8_8_8_AS_16_16_16_16:
case FMT_DXT1_AS_16_16_16_16:
case FMT_DXT2_3_AS_16_16_16_16:
case FMT_DXT4_5_AS_16_16_16_16:
case FMT_2_10_10_10_AS_16_16_16_16:
case FMT_10_11_11_AS_16_16_16_16:
case FMT_11_11_10_AS_16_16_16_16:
case FMT_32_32_32_FLOAT:
case FMT_DXT3A:
case FMT_DXT5A:
case FMT_CTX1:
case FMT_DXT3A_AS_1_1_1_1:
view->format = DXGI_FORMAT_UNKNOWN;
break;
}
return true;
}
void Texture::TextureSwap(uint8_t* dest, const uint8_t* src, uint32_t pitch,
XE_GPU_ENDIAN endianness) {
switch (endianness) {
case XE_GPU_ENDIAN_8IN16:
for (uint32_t i = 0; i < pitch; i += 2, src += 2, dest += 2) {
*(uint16_t*)dest = XESWAP16(*(uint16_t*)src);
}
break;
case XE_GPU_ENDIAN_8IN32: // Swap bytes.
for (uint32_t i = 0; i < pitch; i += 4, src += 4, dest += 4) {
*(uint32_t*)dest = XESWAP32(*(uint32_t*)src);
}
break;
case XE_GPU_ENDIAN_16IN32: // Swap half words.
for (uint32_t i = 0; i < pitch; i += 4, src += 4, dest += 4) {
uint32_t value = *(uint32_t*)src;
*(uint32_t*)dest = ((value >> 16) & 0xFFFF) | (value << 16);
}
break;
default:
case XE_GPU_ENDIAN_NONE:
memcpy(dest, src, pitch);
break;
}
}
// https://code.google.com/p/crunch/source/browse/trunk/inc/crn_decomp.h#4104
uint32_t Texture::TiledOffset2DOuter(uint32_t y, uint32_t width,
uint32_t log_bpp) {
uint32_t macro = ((y >> 5) * (width >> 5)) << (log_bpp + 7);
uint32_t micro = ((y & 6) << 2) << log_bpp;
return macro +
((micro & ~15) << 1) +
(micro & 15) +
((y & 8) << (3 + log_bpp)) +
((y & 1) << 4);
}
uint32_t Texture::TiledOffset2DInner(uint32_t x, uint32_t y, uint32_t bpp,
uint32_t base_offset) {
uint32_t macro = (x >> 5) << (bpp + 7);
uint32_t micro = (x & 7) << bpp;
uint32_t offset = base_offset + (macro + ((micro & ~15) << 1) + (micro & 15));
return ((offset & ~511) << 3) + ((offset & 448) << 2) + (offset & 63) +
((y & 16) << 7) + (((((y & 8) >> 2) + (x >> 3)) & 3) << 6);
}

74
src/xenia/gpu/texture.h Normal file
View File

@ -0,0 +1,74 @@
/**
******************************************************************************
* 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_TEXTURE_H_
#define XENIA_GPU_TEXTURE_H_
#include <xenia/core.h>
#include <xenia/gpu/xenos/xenos.h>
// TODO(benvanik): replace DXGI constants with xenia constants.
#include <d3d11.h>
namespace xe {
namespace gpu {
class Texture;
struct TextureView {
Texture* texture;
int dimensions;
uint32_t width;
uint32_t height;
uint32_t depth;
uint32_t block_size;
uint32_t texel_pitch;
bool is_compressed;
DXGI_FORMAT format;
TextureView()
: texture(nullptr),
dimensions(0),
width(0), height(0), depth(0),
block_size(0), texel_pitch(0),
is_compressed(false), format(DXGI_FORMAT_UNKNOWN) {}
};
class Texture {
public:
Texture(uint32_t address);
virtual ~Texture() = default;
virtual TextureView* Fetch(
const xenos::xe_gpu_texture_fetch_t& fetch) = 0;
protected:
bool FillViewInfo(TextureView* view,
const xenos::xe_gpu_texture_fetch_t& fetch);
static void TextureSwap(uint8_t* dest, const uint8_t* src, uint32_t pitch,
xenos::XE_GPU_ENDIAN endianness);
static uint32_t TiledOffset2DOuter(uint32_t y, uint32_t width,
uint32_t log_bpp);
static uint32_t TiledOffset2DInner(uint32_t x, uint32_t y, uint32_t bpp,
uint32_t base_offset);
uint32_t address_;
};
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_TEXTURE_H_

View File

@ -0,0 +1,45 @@
/**
******************************************************************************
* 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/texture_cache.h>
#include <xenia/gpu/xenos/ucode.h>
using namespace xe;
using namespace xe::gpu;
using namespace xe::gpu::xenos;
// https://github.com/ivmai/bdwgc/blob/master/os_dep.c
TextureCache::TextureCache(Memory* memory)
: memory_(memory) {
}
TextureCache::~TextureCache() {
// textures
}
TextureView* TextureCache::FetchTexture(
uint32_t address, const xenos::xe_gpu_texture_fetch_t& fetch) {
auto it = textures_.find(address);
if (it == textures_.end()) {
// Texture not found.
auto texture = CreateTexture(address, fetch);
if (!texture) {
return nullptr;
}
textures_.insert({ address, texture });
return texture->Fetch(fetch);
} else {
// Texture found.
return it->second->Fetch(fetch);
}
}

View File

@ -0,0 +1,49 @@
/**
******************************************************************************
* 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_TEXTURE_CACHE_H_
#define XENIA_GPU_TEXTURE_CACHE_H_
#include <xenia/core.h>
#include <xenia/gpu/texture.h>
#include <xenia/gpu/xenos/xenos.h>
namespace xe {
namespace gpu {
// TODO(benvanik): overlapping textures.
// TODO(benvanik): multiple textures (differing formats/etc) per address.
class TextureCache {
public:
TextureCache(Memory* memory);
virtual ~TextureCache();
Memory* memory() const { return memory_; }
TextureView* FetchTexture(
uint32_t address, const xenos::xe_gpu_texture_fetch_t& fetch);
protected:
virtual Texture* CreateTexture(
uint32_t address, const xenos::xe_gpu_texture_fetch_t& fetch) = 0;
Memory* memory_;
// Mapped by guest address.
std::unordered_map<uint32_t, Texture*> textures_;
};
} // namespace gpu
} // namespace xe
#endif // XENIA_GPU_TEXTURE_CACHE_H_