Implement experimental support for static environment cube maps to improve support basic reflection in plastic and metallic materials

This commit is contained in:
Rodolfo Bogado 2020-03-31 17:12:48 -03:00
parent ad82a074f8
commit bf7957cfbf
35 changed files with 1893 additions and 1232 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -28,7 +28,7 @@ const std::string scm_rev_str = "Ishiiruka-Dolphin"
#endif
const std::string scm_rev_git_str = SCM_REV_STR;
const std::string scm_rev_cache_str = "202001310028";
const std::string scm_rev_cache_str = "202003081148";
const std::string scm_desc_str = SCM_DESC_STR;
const std::string scm_branch_str = SCM_BRANCH_STR;
const std::string scm_distributor_str = SCM_DISTRIBUTOR_STR;

View file

@ -546,7 +546,7 @@ void CreateRootSignatures()
D3D12_DESCRIPTOR_RANGE desc_range_sampler = {
D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
8, // UINT NumDescriptors;
16, // UINT NumDescriptors;
0, // UINT BaseShaderRegister;
0, // UINT RegisterSpace;
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;

View file

@ -107,6 +107,7 @@ public:
SamplerState desc5;
SamplerState desc6;
SamplerState desc7;
SamplerState desc8;
};
D3D12_GPU_DESCRIPTOR_HANDLE GetHandleForSamplerGroup(SamplerState* sampler_state, unsigned int num_sampler_samples);
@ -136,4 +137,4 @@ private:
std::unordered_map<SamplerStateSet, D3D12_GPU_DESCRIPTOR_HANDLE, hash_sampler_desc> m_sampler_map;
};
} // namespace
} // namespace

View file

@ -15,8 +15,6 @@
namespace DX12
{
namespace D3D
{
constexpr size_t SYNC_TEXTURE_UPLOAD_BUFFER_SIZE = 4 * 512 * 512;
@ -30,7 +28,9 @@ void CleanupPersistentD3DTextureResources()
s_texture_upload_stream_buffer.reset();
}
void ReplaceTexture2D(ID3D12Resource* texture12, const u8* buffer, DXGI_FORMAT fmt, u32 width, u32 height, u32 src_pitch, u32 level, u32 layer, u32 miplevels, u32 layers, D3D12_RESOURCE_STATES current_resource_state)
void ReplaceTexture2D(ID3D12Resource* texture12, const u8* buffer, DXGI_FORMAT fmt, u32 width,
u32 height, u32 src_pitch, u32 level, u32 layer, u32 miplevels, u32 layers,
D3D12_RESOURCE_STATES current_resource_state)
{
u32 pixelsize = 1;
bool compresed = false;
@ -73,7 +73,8 @@ void ReplaceTexture2D(ID3D12Resource* texture12, const u8* buffer, DXGI_FORMAT f
src_pitch *= pixelsize;
height = std::max(1u, (height + 3) >> 2);
}
const u32 upload_size = Common::AlignUpSizePow2(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height;
const u32 upload_size =
Common::AlignUpSizePow2(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height;
ID3D12Resource* upload_buffer = nullptr;
size_t upload_buffer_offset = 0;
@ -84,22 +85,20 @@ void ReplaceTexture2D(ID3D12Resource* texture12, const u8* buffer, DXGI_FORMAT f
// This will only be the case for large (e.g. 8192x8192) textures from custom texture packs.
CD3DX12_HEAP_PROPERTIES hprops(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC rdesc = CD3DX12_RESOURCE_DESC::Buffer(upload_size);
CheckHR(D3D::device->CreateCommittedResource(
&hprops,
D3D12_HEAP_FLAG_NONE,
&rdesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&upload_buffer)));
CheckHR(D3D::device->CreateCommittedResource(&hprops, D3D12_HEAP_FLAG_NONE, &rdesc,
D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
IID_PPV_ARGS(&upload_buffer)));
D3D12_RANGE read_range = {};
CheckHR(upload_buffer->Map(0, &read_range, reinterpret_cast<void**>(&dest_data)));
}
else
{
if (!s_texture_upload_stream_buffer)
s_texture_upload_stream_buffer = std::make_unique<D3DStreamBuffer>(INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr);
s_texture_upload_stream_buffer = std::make_unique<D3DStreamBuffer>(
INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr);
bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(
upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
if (current_command_list_executed)
{
g_renderer->RestoreAPIState();
@ -107,17 +106,22 @@ void ReplaceTexture2D(ID3D12Resource* texture12, const u8* buffer, DXGI_FORMAT f
upload_buffer = s_texture_upload_stream_buffer->GetBuffer();
upload_buffer_offset = s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation();
dest_data = reinterpret_cast<u8*>(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation());
dest_data =
reinterpret_cast<u8*>(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation());
}
ResourceBarrier(current_command_list, texture12, current_resource_state, D3D12_RESOURCE_STATE_COPY_DEST, D3D12CalcSubresource(level, layer, 0, miplevels, layers ));
ResourceBarrier(current_command_list, texture12, current_resource_state,
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12CalcSubresource(level, layer, 0, miplevels, layers));
D3D12_PLACED_SUBRESOURCE_FOOTPRINT upload_footprint = {};
u32 upload_rows = 0;
u64 upload_row_size_in_bytes = 0;
u64 upload_total_bytes = 0;
auto tdesc = texture12->GetDesc();
D3D::device->GetCopyableFootprints(&tdesc, D3D12CalcSubresource(level, layer, 0, miplevels, layers), 1, upload_buffer_offset, &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes);
D3D::device->GetCopyableFootprints(
&tdesc, D3D12CalcSubresource(level, layer, 0, miplevels, layers), 1, upload_buffer_offset,
&upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes);
const u8* src_data = reinterpret_cast<const u8*>(buffer);
if (src_pitch == upload_footprint.Footprint.RowPitch && src_pitch == upload_row_size_in_bytes)
@ -128,49 +132,45 @@ void ReplaceTexture2D(ID3D12Resource* texture12, const u8* buffer, DXGI_FORMAT f
{
for (u32 y = 0; y < upload_rows; ++y)
{
memcpy(
dest_data + upload_footprint.Footprint.RowPitch * y,
src_data + src_pitch * y,
upload_row_size_in_bytes
);
memcpy(dest_data + upload_footprint.Footprint.RowPitch * y, src_data + src_pitch * y,
upload_row_size_in_bytes);
}
}
CD3DX12_TEXTURE_COPY_LOCATION dst = CD3DX12_TEXTURE_COPY_LOCATION(texture12, D3D12CalcSubresource(level, layer, 0, miplevels, layers));
CD3DX12_TEXTURE_COPY_LOCATION src = CD3DX12_TEXTURE_COPY_LOCATION(upload_buffer, upload_footprint);
CD3DX12_TEXTURE_COPY_LOCATION dst = CD3DX12_TEXTURE_COPY_LOCATION(
texture12, D3D12CalcSubresource(level, layer, 0, miplevels, layers));
CD3DX12_TEXTURE_COPY_LOCATION src =
CD3DX12_TEXTURE_COPY_LOCATION(upload_buffer, upload_footprint);
D3D::current_command_list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
// Release temporary buffer after commands complete.
// We block here because otherwise if there was a large number of texture uploads, we may run out of memory.
// We block here because otherwise if there was a large number of texture uploads, we may run out
// of memory.
if (upload_size > MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE)
{
D3D::command_list_mgr->ExecuteQueuedWork(true);
g_renderer->RestoreAPIState();
D3D12_RANGE write_range = { 0, upload_size };
D3D12_RANGE write_range = {0, upload_size};
upload_buffer->Unmap(0, &write_range);
upload_buffer->Release();
}
else if (upload_size > SYNC_TEXTURE_UPLOAD_BUFFER_SIZE)
{
// To grant that the texture data is in place to start rendering we have to execute the copy operation now
// To grant that the texture data is in place to start rendering we have to execute the copy
// operation now
D3D::command_list_mgr->ExecuteQueuedWork();
}
ResourceBarrier(current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST, current_resource_state, D3D12CalcSubresource(level, layer, 0, miplevels, layers));
ResourceBarrier(current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST,
current_resource_state, D3D12CalcSubresource(level, layer, 0, miplevels, layers));
}
} // namespace
} // namespace D3D
D3DTexture2D* D3DTexture2D::Create(u32 width, u32 height, u32 bind, DXGI_FORMAT fmt, u32 levels, u32 slices, D3D12_SUBRESOURCE_DATA* data)
D3DTexture2D* D3DTexture2D::Create(u32 width, u32 height, u32 bind, DXGI_FORMAT fmt, u32 levels,
u32 slices, bool cubemap, D3D12_SUBRESOURCE_DATA* data)
{
ComPtr<ID3D12Resource> texture;
D3D12_RESOURCE_DESC texdesc = CD3DX12_RESOURCE_DESC::Tex2D(
fmt,
width,
height,
slices,
levels
);
D3D12_RESOURCE_DESC texdesc = CD3DX12_RESOURCE_DESC::Tex2D(fmt, width, height, slices, levels);
D3D12_CLEAR_VALUE optimized_clear_value = {};
optimized_clear_value.Format = fmt;
@ -190,24 +190,21 @@ D3DTexture2D* D3DTexture2D::Create(u32 width, u32 height, u32 bind, DXGI_FORMAT
optimized_clear_value.DepthStencil.Depth = 0.0f;
optimized_clear_value.DepthStencil.Stencil = 0;
}
CD3DX12_HEAP_PROPERTIES hprop(D3D12_HEAP_TYPE_DEFAULT);
CheckHR(
D3D::device->CreateCommittedResource(
&hprop,
D3D12_HEAP_FLAG_NONE,
&texdesc,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
&optimized_clear_value,
IID_PPV_ARGS(texture.GetAddressOf())
)
);
CD3DX12_HEAP_PROPERTIES hprop(D3D12_HEAP_TYPE_DEFAULT);
CheckHR(D3D::device->CreateCommittedResource(
&hprop, D3D12_HEAP_FLAG_NONE, &texdesc, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
&optimized_clear_value, IID_PPV_ARGS(texture.GetAddressOf())));
D3D::SetDebugObjectName12(texture.Get(), "Texture created via D3DTexture2D::Create");
D3DTexture2D* ret = new D3DTexture2D(texture.Get(), bind, fmt, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
D3DTexture2D* ret = new D3DTexture2D(texture.Get(), bind, fmt, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, cubemap,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
if (data)
{
DX12::D3D::ReplaceTexture2D(texture.Get(), reinterpret_cast<const u8*>(data->pData), fmt, width, height, static_cast<u32>(data->RowPitch), 0, 0, levels, slices, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
DX12::D3D::ReplaceTexture2D(texture.Get(), reinterpret_cast<const u8*>(data->pData), fmt, width,
height, static_cast<u32>(data->RowPitch), 0, 0, levels, slices,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
}
return ret;
}
@ -230,13 +227,15 @@ UINT D3DTexture2D::Release()
void D3DTexture2D::InitalizeSRV()
{
D3D12_SRV_DIMENSION srv_dim = m_multisampled ? D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
D3D12_SRV_DIMENSION srv_dim = m_multisampled ? D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY :
m_cube ? D3D12_SRV_DIMENSION_TEXTURECUBE :
D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {
m_srv_format, // DXGI_FORMAT Format
srv_dim // D3D12_SRV_DIMENSION ViewDimension
m_srv_format, // DXGI_FORMAT Format
srv_dim // D3D12_SRV_DIMENSION ViewDimension
};
if (srv_dim == D3D12_SRV_DIMENSION_TEXTURE2DARRAY)
if (srv_dim != D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY && srv_dim != D3D12_SRV_DIMENSION_TEXTURECUBE)
{
srv_desc.Texture2DArray.MipLevels = -1;
srv_desc.Texture2DArray.MostDetailedMip = 0;
@ -258,10 +257,11 @@ void D3DTexture2D::InitalizeSRV()
void D3DTexture2D::InitalizeDSV()
{
D3D12_DSV_DIMENSION dsv_dim = m_multisampled ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
D3D12_DSV_DIMENSION dsv_dim =
m_multisampled ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {
m_dsv_format, // DXGI_FORMAT Format
dsv_dim, // D3D12_DSV_DIMENSION
m_dsv_format, // DXGI_FORMAT Format
dsv_dim, // D3D12_DSV_DIMENSION
D3D12_DSV_FLAG_NONE // D3D12_DSV_FLAG Flags
};
@ -276,10 +276,11 @@ void D3DTexture2D::InitalizeDSV()
void D3DTexture2D::InitalizeRTV()
{
D3D12_RTV_DIMENSION rtv_dim = m_multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
D3D12_RTV_DIMENSION rtv_dim =
m_multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {
m_rtv_format, // DXGI_FORMAT Format
rtv_dim // D3D12_RTV_DIMENSION ViewDimension
m_rtv_format, // DXGI_FORMAT Format
rtv_dim // D3D12_RTV_DIMENSION ViewDimension
};
if (rtv_dim == D3D12_RTV_DIMENSION_TEXTURE2DARRAY)
@ -292,8 +293,11 @@ void D3DTexture2D::InitalizeRTV()
}
D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, u32 bind, DXGI_FORMAT fmt,
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled, D3D12_RESOURCE_STATES resource_state)
: m_format(fmt), m_tex(texptr), m_srv_format(srv_format), m_dsv_format(dsv_format), m_rtv_format(rtv_format), m_resource_state(resource_state), m_multisampled(multisampled), m_bind_falgs(bind)
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format,
bool multisampled, bool cube, D3D12_RESOURCE_STATES resource_state)
: m_format(fmt), m_tex(texptr), m_srv_format(srv_format), m_dsv_format(dsv_format),
m_rtv_format(rtv_format), m_resource_state(resource_state), m_multisampled(multisampled),
m_cube(cube), m_bind_falgs(bind)
{
if (m_bind_falgs & TEXTURE_BIND_FLAG_SHADER_RESOURCE)
{
@ -314,15 +318,18 @@ D3DTexture2D::~D3DTexture2D()
DX12::D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_tex.Detach());
if (m_bind_falgs & TEXTURE_BIND_FLAG_SHADER_RESOURCE)
{
D3D::command_list_mgr->FreeDescriptorAfterCurrentCommandListExecuted(D3D::gpu_descriptor_heap_mgr.get(), m_srv_index);
D3D::command_list_mgr->FreeDescriptorAfterCurrentCommandListExecuted(
D3D::gpu_descriptor_heap_mgr.get(), m_srv_index);
}
if (m_bind_falgs & TEXTURE_BIND_FLAG_RENDER_TARGET)
{
D3D::command_list_mgr->FreeDescriptorAfterCurrentCommandListExecuted(D3D::rtv_descriptor_heap_mgr.get(), m_rtv_index);
D3D::command_list_mgr->FreeDescriptorAfterCurrentCommandListExecuted(
D3D::rtv_descriptor_heap_mgr.get(), m_rtv_index);
}
if (m_bind_falgs & TEXTURE_BIND_FLAG_DEPTH_STENCIL)
{
D3D::command_list_mgr->FreeDescriptorAfterCurrentCommandListExecuted(D3D::dsv_descriptor_heap_mgr.get(), m_dsv_index);
D3D::command_list_mgr->FreeDescriptorAfterCurrentCommandListExecuted(
D3D::dsv_descriptor_heap_mgr.get(), m_dsv_index);
}
}

View file

@ -41,6 +41,7 @@ public:
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN,
bool multisampled = false,
bool cube = false,
D3D12_RESOURCE_STATES resource_state = D3D12_RESOURCE_STATE_COMMON);
static D3DTexture2D* Create(u32 width,
u32 height,
@ -48,6 +49,7 @@ public:
DXGI_FORMAT fmt,
u32 levels = 1,
u32 slices = 1,
bool cubemap = false,
D3D12_SUBRESOURCE_DATA* data = nullptr);
void TransitionToResourceState(ID3D12GraphicsCommandList* command_list, D3D12_RESOURCE_STATES state_after)
{
@ -128,6 +130,7 @@ private:
D3D12_RESOURCE_STATES m_resource_state = D3D12_RESOURCE_STATE_COMMON;
bool m_multisampled{};
bool m_cube{};
std::atomic<unsigned long> m_ref = 1;
u32 m_bind_falgs = {};

View file

@ -79,6 +79,7 @@ DXTexture::DXTexture(const TextureConfig& tex_config) : HostTexture(tex_config)
DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN,
false,
m_config.enviroment,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE
);
// EXISTINGD3D11TODO: better debug names

View file

@ -285,7 +285,7 @@ void XFBSource::CopyEFB(float gamma)
texdesc.Format,
DXGI_FORMAT_UNKNOWN,
texdesc.Format,
false,
false, false,
D3D12_RESOURCE_STATE_RENDER_TARGET
);
}

View file

@ -89,7 +89,7 @@ typedef struct _Nv_Stereo_Image_Header
// GX pipeline state
struct GXPipelineState
{
std::array<SamplerState, 8> samplers;
std::array<SamplerState, 9> samplers;
BlendingState blend;
DepthState zmode;
RasterizationState raster;

View file

@ -23,25 +23,23 @@
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/LookUpTables.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/TextureScalerCommon.h"
#include "VideoCommon/VideoConfig.h"
namespace DX12
{
static std::unique_ptr<TextureEncoder> s_encoder;
static std::unique_ptr<D3DStreamBuffer> s_efb_copy_stream_buffer = nullptr;
static u32 s_efb_copy_last_cbuf_id = UINT_MAX;
static D3D12_GPU_DESCRIPTOR_HANDLE s_group_base_texture_gpu_handle = { 0 };
static D3D12_GPU_DESCRIPTOR_HANDLE s_group_base_texture_gpu_handle = {0};
static bool s_handle_changed = false;
D3D12_GPU_DESCRIPTOR_HANDLE TextureCache::GetTextureGroupHandle()
{
D3D12_GPU_DESCRIPTOR_HANDLE Handle = { 0 };
D3D12_GPU_DESCRIPTOR_HANDLE Handle = {0};
if (s_handle_changed)
{
s_handle_changed = false;
@ -50,10 +48,12 @@ D3D12_GPU_DESCRIPTOR_HANDLE TextureCache::GetTextureGroupHandle()
return Handle;
}
HostTextureFormat TextureCache::GetHostTextureFormat(const s32 texformat, const TlutFormat tlutfmt, u32 width, u32 height)
HostTextureFormat TextureCache::GetHostTextureFormat(const s32 texformat, const TlutFormat tlutfmt,
u32 width, u32 height)
{
const bool compressed_supported = ((width & 3) == 0) && ((height & 3) == 0);
HostTextureFormat pcfmt = TexDecoder::GetHostTextureFormat(texformat, tlutfmt, compressed_supported);
HostTextureFormat pcfmt =
TexDecoder::GetHostTextureFormat(texformat, tlutfmt, compressed_supported);
pcfmt = !g_ActiveConfig.backend_info.bSupportedFormats[pcfmt] ? PC_TEX_FMT_RGBA32 : pcfmt;
return pcfmt;
}
@ -63,39 +63,40 @@ std::unique_ptr<HostTexture> TextureCache::CreateTexture(const TextureConfig& co
return std::make_unique<DXTexture>(config);
}
void TextureCache::CopyEFBToCacheEntry(TextureCacheBase::TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
bool scale_by_half, u32 cbuf_id, const float* colmat, u32 width, u32 height)
void TextureCache::CopyEFBToCacheEntry(TextureCacheBase::TCacheEntry* entry, bool is_depth_copy,
const EFBRectangle& src_rect, bool scale_by_half,
u32 cbuf_id, const float* colmat, u32 width, u32 height)
{
// When copying at half size, in multisampled mode, resolve the color/depth buffer first.
// This is because multisampled texture reads go through Load, not Sample, and the linear
// filter is ignored.
bool multisampled = (g_ActiveConfig.iMultisamples > 1);
D3DTexture2D* efb_tex = is_depth_copy ?
FramebufferManager::GetEFBDepthTexture() :
FramebufferManager::GetEFBColorTexture();
D3DTexture2D* efb_tex = is_depth_copy ? FramebufferManager::GetEFBDepthTexture() :
FramebufferManager::GetEFBColorTexture();
const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(src_rect);
if (multisampled && scale_by_half)
{
multisampled = false;
efb_tex = is_depth_copy ?
FramebufferManager::GetResolvedEFBDepthTexture() :
FramebufferManager::GetResolvedEFBColorTexture();
efb_tex = is_depth_copy ? FramebufferManager::GetResolvedEFBDepthTexture() :
FramebufferManager::GetResolvedEFBColorTexture();
}
// set transformation
if (s_efb_copy_last_cbuf_id != cbuf_id)
{
s_efb_copy_stream_buffer->AllocateSpaceInBuffer(28 * sizeof(float), 256);
memcpy(s_efb_copy_stream_buffer->GetCPUAddressOfCurrentAllocation(), colmat, 28 * sizeof(float));
memcpy(s_efb_copy_stream_buffer->GetCPUAddressOfCurrentAllocation(), colmat,
28 * sizeof(float));
s_efb_copy_last_cbuf_id = cbuf_id;
}
// stretch picture with increased internal resolution
D3D::SetViewportAndScissor(0, 0, width, height);
D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, s_efb_copy_stream_buffer->GetGPUAddressOfCurrentAllocation());
D3D::current_command_list->SetGraphicsRootConstantBufferView(
DESCRIPTOR_TABLE_PS_CBVONE, s_efb_copy_stream_buffer->GetGPUAddressOfCurrentAllocation());
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true);
// TODO: try targetSource.asRECT();
const D3D12_RECT sourcerect = CD3DX12_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
const D3D12_RECT sourcerect =
CD3DX12_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom);
// Use linear filtering if (bScaleByHalf), use point filtering otherwise
if (scale_by_half)
@ -106,44 +107,35 @@ void TextureCache::CopyEFBToCacheEntry(TextureCacheBase::TCacheEntry* entry, boo
// Make sure we don't draw with the texture set as both a source and target.
// (This can happen because we don't unbind textures when we free them.)
auto destination = static_cast<DXTexture*>(entry->texture.get())->GetRawTexIdentifier();
destination->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
destination->TransitionToResourceState(D3D::current_command_list,
D3D12_RESOURCE_STATE_RENDER_TARGET);
auto rtv = destination->GetRTV();
D3D::current_command_list->OMSetRenderTargets(1, &rtv, FALSE, nullptr);
// Create texture copy
D3D::DrawShadedTexQuad(
efb_tex,
&sourcerect,
g_renderer->GetTargetWidth(),
g_renderer->GetTargetHeight(),
is_depth_copy ? StaticShaderCache::GetDepthMatrixPixelShader(multisampled)
: StaticShaderCache::GetColorMatrixPixelShader(multisampled),
StaticShaderCache::GetSimpleVertexShader(),
StaticShaderCache::GetSimpleVertexShaderInputLayout(),
StaticShaderCache::GetCopyGeometryShader(),
0, destination->GetFormat(), false, destination->GetMultisampled()
);
destination->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
efb_tex, &sourcerect, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(),
is_depth_copy ? StaticShaderCache::GetDepthMatrixPixelShader(multisampled) :
StaticShaderCache::GetColorMatrixPixelShader(multisampled),
StaticShaderCache::GetSimpleVertexShader(),
StaticShaderCache::GetSimpleVertexShaderInputLayout(),
StaticShaderCache::GetCopyGeometryShader(), 0, destination->GetFormat(), false,
destination->GetMultisampled());
destination->TransitionToResourceState(D3D::current_command_list,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_renderer->RestoreAPIState();
}
void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width,
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride,
bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half)
{
s_encoder->Encode(dst,
format,
native_width,
bytes_per_row,
num_blocks_y,
memory_stride,
is_depth_copy,
src_rect,
scale_by_half);
s_encoder->Encode(dst, format, native_width, bytes_per_row, num_blocks_y, memory_stride,
is_depth_copy, src_rect, scale_by_half);
}
static const constexpr char s_palette_shader_hlsl[] =
R"HLSL(
R"HLSL(
sampler samp0 : register(s0);
Texture2DArray Tex0 : register(t0);
Buffer<uint> Tex1 : register(t1);
@ -230,7 +222,8 @@ void TextureCache::LoadLut(u32 lutFmt, void* palette, u32 size)
}
if (lutFmt == m_lut_format && palette == m_addr && size == m_lut_size && m_hash)
{
u64 hash = GetHash64(reinterpret_cast<u8*>(palette), size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
u64 hash = GetHash64(reinterpret_cast<u8*>(palette), size,
g_ActiveConfig.iSafeTextureCache_ColorSamples);
if (hash == m_hash)
{
return;
@ -239,7 +232,8 @@ void TextureCache::LoadLut(u32 lutFmt, void* palette, u32 size)
}
else
{
m_hash = GetHash64(reinterpret_cast<u8*>(palette), size, g_ActiveConfig.iSafeTextureCache_ColorSamples);
m_hash = GetHash64(reinterpret_cast<u8*>(palette), size,
g_ActiveConfig.iSafeTextureCache_ColorSamples);
}
m_lut_format = (TlutFormat)lutFmt;
m_lut_size = size;
@ -249,7 +243,8 @@ void TextureCache::LoadLut(u32 lutFmt, void* palette, u32 size)
// Only 1024 palette buffers are supported in flight at once (arbitrary, this should be plenty).
const u32 palette_buffer_allocation_size = 512;
m_palette_stream_buffer->AllocateSpaceInBuffer(palette_buffer_allocation_size, 256);
memcpy(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation(), palette, palette_buffer_allocation_size);
memcpy(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation(), palette,
palette_buffer_allocation_size);
}
bool TextureCache::Palettize(TCacheEntry* entry, const TCacheEntry* base_entry)
@ -258,19 +253,23 @@ bool TextureCache::Palettize(TCacheEntry* entry, const TCacheEntry* base_entry)
{
return false;
}
D3DTexture2D* base_texture = static_cast<DXTexture*>(base_entry->texture.get())->GetRawTexIdentifier();
D3DTexture2D* base_texture =
static_cast<DXTexture*>(base_entry->texture.get())->GetRawTexIdentifier();
D3DTexture2D* dst_texture = static_cast<DXTexture*>(entry->texture.get())->GetRawTexIdentifier();
// D3D12: Because the second SRV slot is occupied by this buffer, and an arbitrary texture occupies the first SRV slot,
// we need to allocate temporary space out of our descriptor heap, place the palette SRV in the second slot, then copy the
// existing texture's descriptor into the first slot.
// D3D12: Because the second SRV slot is occupied by this buffer, and an arbitrary texture
// occupies the first SRV slot, we need to allocate temporary space out of our descriptor heap,
// place the palette SRV in the second slot, then copy the existing texture's descriptor into the
// first slot.
// First, allocate the (temporary) space in the descriptor heap.
D3D12_CPU_DESCRIPTOR_HANDLE srv_group_cpu_handle[2] = {};
D3D12_GPU_DESCRIPTOR_HANDLE srv_group_gpu_handle[2] = {};
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(2, srv_group_cpu_handle, srv_group_gpu_handle))
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(2, srv_group_cpu_handle,
srv_group_gpu_handle))
{
D3D::command_list_mgr->ExecuteQueuedWork();
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(2, srv_group_cpu_handle, srv_group_gpu_handle))
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(2, srv_group_cpu_handle,
srv_group_gpu_handle))
{
PanicAlert("Failed to allocate temporary descriptors.");
return false;
@ -281,71 +280,69 @@ bool TextureCache::Palettize(TCacheEntry* entry, const TCacheEntry* base_entry)
// Now, create the palette SRV at the appropriate offset.
D3D12_SHADER_RESOURCE_VIEW_DESC palette_buffer_srv_desc = {
DXGI_FORMAT_R16_UINT, // DXGI_FORMAT Format;
D3D12_SRV_DIMENSION_BUFFER, // D3D12_SRV_DIMENSION ViewDimension;
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING // UINT Shader4ComponentMapping;
DXGI_FORMAT_R16_UINT, // DXGI_FORMAT Format;
D3D12_SRV_DIMENSION_BUFFER, // D3D12_SRV_DIMENSION ViewDimension;
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING // UINT Shader4ComponentMapping;
};
// Each 'element' is two bytes since format is R16.
palette_buffer_srv_desc.Buffer.FirstElement = m_palette_stream_buffer->GetOffsetOfCurrentAllocation() / sizeof(u16);
palette_buffer_srv_desc.Buffer.FirstElement =
m_palette_stream_buffer->GetOffsetOfCurrentAllocation() / sizeof(u16);
palette_buffer_srv_desc.Buffer.NumElements = 256;
D3D::device->CreateShaderResourceView(m_palette_stream_buffer->GetBuffer(), &palette_buffer_srv_desc, srv_group_cpu_handle[1]);
D3D::device->CreateShaderResourceView(m_palette_stream_buffer->GetBuffer(),
&palette_buffer_srv_desc, srv_group_cpu_handle[1]);
// Now, copy the existing texture's descriptor into the new temporary location.
base_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
D3D::device->CopyDescriptorsSimple(
1,
srv_group_cpu_handle[0],
base_texture->GetSRVCPUShadow(),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV
);
base_texture->TransitionToResourceState(D3D::current_command_list,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
D3D::device->CopyDescriptorsSimple(1, srv_group_cpu_handle[0], base_texture->GetSRVCPUShadow(),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
// Finally, bind our temporary location.
D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV, srv_group_gpu_handle[0]);
D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV,
srv_group_gpu_handle[0]);
// D3D11EXISTINGTODO: Add support for C14X2 format. (Different multiplier, more palette entries.)
// D3D12: See TextureCache::TextureCache() - because there are only two possible buffer contents here,
// just pre-populate the data in two parts of the same upload heap.
// D3D12: See TextureCache::TextureCache() - because there are only two possible buffer contents
// here, just pre-populate the data in two parts of the same upload heap.
if ((base_entry->format & 0xf) == GX_TF_I4)
{
D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress());
D3D::current_command_list->SetGraphicsRootConstantBufferView(
DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress());
}
else
{
D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress() + 256);
D3D::current_command_list->SetGraphicsRootConstantBufferView(
DESCRIPTOR_TABLE_PS_CBVONE, m_palette_uniform_buffer->GetGPUVirtualAddress() + 256);
}
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true);
const D3D12_RECT source_rect = CD3DX12_RECT(0, 0, base_entry->GetConfig().width, base_entry->GetConfig().height);
const D3D12_RECT source_rect =
CD3DX12_RECT(0, 0, base_entry->GetConfig().width, base_entry->GetConfig().height);
D3D::SetPointCopySampler();
// Make sure we don't draw with the texture set as both a source and target.
// (This can happen because we don't unbind textures when we free them.)
dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
dst_texture->TransitionToResourceState(D3D::current_command_list,
D3D12_RESOURCE_STATE_RENDER_TARGET);
auto rtv = dst_texture->GetRTV();
D3D::current_command_list->OMSetRenderTargets(1, &rtv, FALSE, nullptr);
// stretch picture with increased internal resolution
// stretch picture with increased internal resolution
D3D::SetViewportAndScissor(0, 0, base_entry->GetConfig().width, base_entry->GetConfig().height);
// Create texture copy
D3D::DrawShadedTexQuad(
base_texture,
&source_rect, base_entry->GetConfig().width,
base_entry->GetConfig().height,
m_palette_pixel_shaders[m_lut_format],
StaticShaderCache::GetSimpleVertexShader(),
StaticShaderCache::GetSimpleVertexShaderInputLayout(),
StaticShaderCache::GetCopyGeometryShader(),
0,
dst_texture->GetFormat(),
true,
dst_texture->GetMultisampled()
);
dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
D3D::DrawShadedTexQuad(base_texture, &source_rect, base_entry->GetConfig().width,
base_entry->GetConfig().height, m_palette_pixel_shaders[m_lut_format],
StaticShaderCache::GetSimpleVertexShader(),
StaticShaderCache::GetSimpleVertexShaderInputLayout(),
StaticShaderCache::GetCopyGeometryShader(), 0, dst_texture->GetFormat(),
true, dst_texture->GetMultisampled());
dst_texture->TransitionToResourceState(D3D::current_command_list,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_renderer->RestoreAPIState();
return true;
}
@ -360,7 +357,7 @@ D3D12_SHADER_BYTECODE GetConvertShader(const std::string& type)
D3DBlob* Blob = nullptr;
D3D::CompilePixelShader(shader, &Blob);
return{ Blob->Data(), Blob->Size() };
return {Blob->Data(), Blob->Size()};
}
TextureCache::TextureCache()
@ -376,36 +373,38 @@ TextureCache::TextureCache()
m_palette_pixel_shaders[GX_TL_RGB565] = GetConvertShader("RGB565");
m_palette_pixel_shaders[GX_TL_RGB5A3] = GetConvertShader("RGB5A3");
m_palette_stream_buffer = std::make_unique<D3DStreamBuffer>(sizeof(u16) * 256 * 1024, sizeof(u16) * 256 * 1024 * 16, nullptr);
m_palette_stream_buffer = std::make_unique<D3DStreamBuffer>(
sizeof(u16) * 256 * 1024, sizeof(u16) * 256 * 1024 * 16, nullptr);
// Right now, there are only two variants of palette_uniform data. So, we'll just create an upload heap to permanently store both of these.
// Right now, there are only two variants of palette_uniform data. So, we'll just create an upload
// heap to permanently store both of these.
CD3DX12_HEAP_PROPERTIES hprop(D3D12_HEAP_TYPE_DEFAULT);
auto rdesc = CD3DX12_RESOURCE_DESC::Buffer(((16 + 255) & ~255) * 2);
CheckHR(
D3D::device->CreateCommittedResource(
&hprop,
D3D12_HEAP_FLAG_NONE,
&rdesc, // Constant Buffers have to be 256b aligned. "* 2" to create for two sets of data.
D3D12_RESOURCE_STATE_COPY_DEST,
nullptr,
IID_PPV_ARGS(&m_palette_uniform_buffer)
)
);
CheckHR(D3D::device->CreateCommittedResource(
&hprop, D3D12_HEAP_FLAG_NONE,
&rdesc, // Constant Buffers have to be 256b aligned. "* 2" to create for two sets of data.
D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&m_palette_uniform_buffer)));
D3D::SetDebugObjectName12(m_palette_uniform_buffer, "a constant buffer used in TextureCache::ConvertTexture");
D3D::SetDebugObjectName12(m_palette_uniform_buffer,
"a constant buffer used in TextureCache::ConvertTexture");
// Temporarily repurpose m_palette_stream_buffer as a copy source to populate initial data here.
m_palette_stream_buffer->AllocateSpaceInBuffer(256 * 2, 256);
u8* upload_heap_data_location = reinterpret_cast<u8*>(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation());
u8* upload_heap_data_location =
reinterpret_cast<u8*>(m_palette_stream_buffer->GetCPUAddressOfCurrentAllocation());
memset(upload_heap_data_location, 0, 256 * 2);
float paramsFormatZero[4] = { 15.f };
float paramsFormatNonzero[4] = { 255.f };
float paramsFormatZero[4] = {15.f};
float paramsFormatNonzero[4] = {255.f};
memcpy(upload_heap_data_location, paramsFormatZero, sizeof(paramsFormatZero));
memcpy(upload_heap_data_location + 256, paramsFormatNonzero, sizeof(paramsFormatNonzero));
D3D::current_command_list->CopyBufferRegion(m_palette_uniform_buffer, 0, m_palette_stream_buffer->GetBuffer(), m_palette_stream_buffer->GetOffsetOfCurrentAllocation(), 256 * 2);
DX12::D3D::ResourceBarrier(D3D::current_command_list, m_palette_uniform_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, 0);
D3D::current_command_list->CopyBufferRegion(
m_palette_uniform_buffer, 0, m_palette_stream_buffer->GetBuffer(),
m_palette_stream_buffer->GetOffsetOfCurrentAllocation(), 256 * 2);
DX12::D3D::ResourceBarrier(D3D::current_command_list, m_palette_uniform_buffer,
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, 0);
}
TextureCache::~TextureCache()
@ -432,27 +431,29 @@ void TextureCache::BindTextures()
}
if (last_texture == bound_textures.size())
{
DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(
DESCRIPTOR_TABLE_PS_SRV,
DX12::D3D::null_srv_gpu);
DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV,
DX12::D3D::null_srv_gpu);
return;
}
if (last_texture == 0 && !bound_textures[0]->material_map)
{
DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(
DESCRIPTOR_TABLE_PS_SRV,
static_cast<DXTexture*>(bound_textures[0]->texture.get())->GetRawTexIdentifier()->GetSRVGPU());
DESCRIPTOR_TABLE_PS_SRV, static_cast<DXTexture*>(bound_textures[0]->texture.get())
->GetRawTexIdentifier()
->GetSRVGPU());
return;
}
// If more than one texture, allocate space for group.
D3D12_CPU_DESCRIPTOR_HANDLE s_group_base_texture_cpu_handle;
const u32 num_handles = 8;
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(num_handles, &s_group_base_texture_cpu_handle, &s_group_base_texture_gpu_handle))
const u32 num_handles = g_ActiveConfig.bForcePhongShading ? 9 : 8;
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(
num_handles, &s_group_base_texture_cpu_handle, &s_group_base_texture_gpu_handle))
{
// Kick command buffer before attempting to allocate again. This is slow.
D3D::command_list_mgr->ExecuteQueuedWork();
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(num_handles, &s_group_base_texture_cpu_handle, &s_group_base_texture_gpu_handle))
if (!D3D::gpu_descriptor_heap_mgr->AllocateTemporary(
num_handles, &s_group_base_texture_cpu_handle, &s_group_base_texture_gpu_handle))
{
PanicAlert("Failed to allocate temporary descriptors.");
return;
@ -465,27 +466,58 @@ void TextureCache::BindTextures()
{
D3D12_CPU_DESCRIPTOR_HANDLE textureDestDescriptor;
textureDestDescriptor.ptr =
s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size;
s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size;
DX12::D3D::device->CopyDescriptorsSimple(
1, textureDestDescriptor, static_cast<DXTexture*>(bound_textures[stage]->texture.get())->GetRawTexIdentifier()->GetSRVCPUShadow(),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1, textureDestDescriptor,
static_cast<DXTexture*>(bound_textures[stage]->texture.get())
->GetRawTexIdentifier()
->GetSRVCPUShadow(),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
else
{
D3D12_CPU_DESCRIPTOR_HANDLE nullDestDescriptor;
nullDestDescriptor.ptr =
s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size;
s_group_base_texture_cpu_handle.ptr + stage * D3D::resource_descriptor_size;
DX12::D3D::device->CopyDescriptorsSimple(1, nullDestDescriptor,
DX12::D3D::null_srv_cpu_shadow,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
DX12::D3D::null_srv_cpu_shadow,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
}
if (g_ActiveConfig.HiresMaterialMapsEnabled() && g_ActiveConfig.bForcePhongShading)
{
SetupEnviromentTexture();
if (bound_enviroment)
{
D3D12_CPU_DESCRIPTOR_HANDLE textureDestDescriptor;
textureDestDescriptor.ptr =
s_group_base_texture_cpu_handle.ptr + 8 * D3D::resource_descriptor_size;
DX12::D3D::device->CopyDescriptorsSimple(
1, textureDestDescriptor,
static_cast<DXTexture*>(bound_enviroment->texture.get())
->GetRawTexIdentifier()
->GetSRVCPUShadow(),
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
else
{
D3D12_CPU_DESCRIPTOR_HANDLE nullDestDescriptor;
nullDestDescriptor.ptr =
s_group_base_texture_cpu_handle.ptr + 8 * D3D::resource_descriptor_size;
DX12::D3D::device->CopyDescriptorsSimple(1, nullDestDescriptor,
DX12::D3D::null_srv_cpu_shadow,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
}
// Actually bind the textures.
DX12::D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_SRV,
s_group_base_texture_gpu_handle);
s_group_base_texture_gpu_handle);
}
}
} // namespace DX12

View file

@ -184,11 +184,11 @@ void VideoBackend::Video_Prepare()
{
// internal interfaces
g_renderer = std::make_unique<Renderer>(m_window_handle);
g_renderer->Init();
g_texture_cache = std::make_unique<TextureCache>();
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();
g_xfb_encoder = std::make_unique<XFBEncoder>();
g_renderer->Init();
ShaderCache::Init();
ShaderConstantsManager::Init();
StaticShaderCache::Init();

View file

@ -1,21 +1,23 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoCommon/TextureUtil.h"
#include "VideoBackends/DX11/D3DBase.h"
#include "VideoBackends/DX11/D3DTexture.h"
#include "Common/CommonTypes.h"
#include "Common/MsgHandler.h"
#include "VideoBackends/DX11/D3DBase.h"
#include "VideoCommon/TextureUtil.h"
namespace DX11
{
namespace D3D
{
inline void LoadDataMap(ID3D11Texture2D* pTexture, const u8* buffer, const s32 level, s32 width, s32 height, s32 pitch, u32 layer, u32 miplevels, DXGI_FORMAT fmt, bool swap_rb, bool convert_rgb565)
inline void LoadDataMap(ID3D11Texture2D* pTexture, const u8* buffer, const s32 level, s32 width,
s32 height, s32 pitch, u32 layer, u32 miplevels, DXGI_FORMAT fmt,
bool swap_rb, bool convert_rgb565)
{
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr = D3D::context->Map(pTexture, D3D11CalcSubresource(level, layer, miplevels), D3D11_MAP_WRITE_DISCARD, 0, &map);
HRESULT hr = D3D::context->Map(pTexture, D3D11CalcSubresource(level, layer, miplevels),
D3D11_MAP_WRITE_DISCARD, 0, &map);
if (FAILED(hr) || !map.pData)
{
PanicAlert("Failed to map texture in %s %d\n", __FILE__, __LINE__);
@ -33,21 +35,24 @@ inline void LoadDataMap(ID3D11Texture2D* pTexture, const u8* buffer, const s32 l
break;
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R32_FLOAT:
case DXGI_FORMAT_R32_FLOAT:
if (convert_rgb565)
{
if (fmt == DXGI_FORMAT_B8G8R8A8_UNORM)
{
TextureUtil::ConvertRGBA565_BGRA((u32 *)map.pData, map.RowPitch >> 2, (u16*)buffer, width, height, pitch);
TextureUtil::ConvertRGBA565_BGRA((u32*)map.pData, map.RowPitch >> 2, (u16*)buffer, width,
height, pitch);
}
else
{
TextureUtil::ConvertRGBA565_BGRA((u32 *)map.pData, map.RowPitch >> 2, (u16*)buffer, width, height, pitch);
TextureUtil::ConvertRGBA565_BGRA((u32*)map.pData, map.RowPitch >> 2, (u16*)buffer, width,
height, pitch);
}
}
else if (swap_rb)
{
TextureUtil::ConvertRGBA_BGRA((u32 *)map.pData, map.RowPitch, (u32*)buffer, width, height, pitch);
TextureUtil::ConvertRGBA_BGRA((u32*)map.pData, map.RowPitch, (u32*)buffer, width, height,
pitch);
}
else
{
@ -58,7 +63,8 @@ inline void LoadDataMap(ID3D11Texture2D* pTexture, const u8* buffer, const s32 l
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC7_UNORM:
TextureUtil::CopyCompressedTextureData((u8*)map.pData, buffer, width, height, pitch, fmt == DXGI_FORMAT_BC1_UNORM ? 8 : 16, map.RowPitch);
TextureUtil::CopyCompressedTextureData((u8*)map.pData, buffer, width, height, pitch,
fmt == DXGI_FORMAT_BC1_UNORM ? 8 : 16, map.RowPitch);
break;
case DXGI_FORMAT_R16G16B16A16_FLOAT:
pixelsize = 8;
@ -71,12 +77,15 @@ inline void LoadDataMap(ID3D11Texture2D* pTexture, const u8* buffer, const s32 l
}
if (pixelsize > 0)
{
TextureUtil::CopyTextureData((u8*)map.pData, buffer, width, height, pitch * pixelsize, map.RowPitch, pixelsize);
TextureUtil::CopyTextureData((u8*)map.pData, buffer, width, height, pitch * pixelsize,
map.RowPitch, pixelsize);
}
D3D::context->Unmap(pTexture, level);
}
inline void LoadDataResource(ID3D11Texture2D* pTexture, const u8* buffer, const s32 level, s32 width, s32 height, s32 pitch, u32 layer, u32 miplevels, DXGI_FORMAT fmt, bool swap_rb)
inline void LoadDataResource(ID3D11Texture2D* pTexture, const u8* buffer, const s32 level,
s32 width, s32 height, s32 pitch, u32 layer, u32 miplevels,
DXGI_FORMAT fmt, bool swap_rb)
{
s32 pixelsize = 0;
switch (fmt)
@ -94,7 +103,7 @@ inline void LoadDataResource(ID3D11Texture2D* pTexture, const u8* buffer, const
pixelsize = 4;
if (swap_rb)
{
TextureUtil::ConvertRGBA_BGRA((u32 *)buffer, pitch * 4, (u32*)buffer, width, height, pitch);
TextureUtil::ConvertRGBA_BGRA((u32*)buffer, pitch * 4, (u32*)buffer, width, height, pitch);
}
break;
case DXGI_FORMAT_BC1_UNORM:
@ -102,7 +111,7 @@ inline void LoadDataResource(ID3D11Texture2D* pTexture, const u8* buffer, const
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC7_UNORM:
pitch = (pitch + 3) >> 2;
pixelsize = (fmt == DXGI_FORMAT_BC1_UNORM ? 8 : 16);
pixelsize = (fmt == DXGI_FORMAT_BC1_UNORM ? 8 : 16);
break;
case DXGI_FORMAT_R16G16B16A16_FLOAT:
pixelsize = 8;
@ -115,15 +124,19 @@ inline void LoadDataResource(ID3D11Texture2D* pTexture, const u8* buffer, const
}
if (pixelsize > 0)
{
D3D::context->UpdateSubresource(pTexture, D3D11CalcSubresource(level, layer, miplevels), nullptr, buffer, pixelsize * pitch, 0);
D3D::context->UpdateSubresource(pTexture, D3D11CalcSubresource(level, layer, miplevels),
nullptr, buffer, pixelsize * pitch, 0);
}
}
void ReplaceTexture2D(ID3D11Texture2D* pTexture, const u8* buffer, u32 width, u32 height, u32 pitch, u32 level, u32 layer, u32 miplevels, D3D11_USAGE usage, DXGI_FORMAT fmt, bool swap_rb, bool convert_rgb565)
void ReplaceTexture2D(ID3D11Texture2D* pTexture, const u8* buffer, u32 width, u32 height, u32 pitch,
u32 level, u32 layer, u32 miplevels, D3D11_USAGE usage, DXGI_FORMAT fmt,
bool swap_rb, bool convert_rgb565)
{
if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING)
{
LoadDataMap(pTexture, buffer, level, width, height, pitch, layer, miplevels, fmt, swap_rb, convert_rgb565);
LoadDataMap(pTexture, buffer, level, width, height, pitch, layer, miplevels, fmt, swap_rb,
convert_rgb565);
}
else
{
@ -131,18 +144,24 @@ void ReplaceTexture2D(ID3D11Texture2D* pTexture, const u8* buffer, u32 width, u3
}
}
} // namespace
} // namespace D3D
D3DTexture2D* D3DTexture2D::Create(u32 width, u32 height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, u32 levels, u32 slices, D3D11_SUBRESOURCE_DATA* data)
D3DTexture2D* D3DTexture2D::Create(u32 width, u32 height, D3D11_BIND_FLAG bind, D3D11_USAGE usage,
DXGI_FORMAT fmt, u32 levels, u32 slices,
D3D11_SUBRESOURCE_DATA* data)
{
ID3D11Texture2D* pTexture = nullptr;
HRESULT hr;
D3D11_CPU_ACCESS_FLAG cpuflags;
if (usage == D3D11_USAGE_STAGING) cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE | (int)D3D11_CPU_ACCESS_READ);
else if (usage == D3D11_USAGE_DYNAMIC) cpuflags = D3D11_CPU_ACCESS_WRITE;
else cpuflags = (D3D11_CPU_ACCESS_FLAG)0;
D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags);
if (usage == D3D11_USAGE_STAGING)
cpuflags = (D3D11_CPU_ACCESS_FLAG)((int)D3D11_CPU_ACCESS_WRITE | (int)D3D11_CPU_ACCESS_READ);
else if (usage == D3D11_USAGE_DYNAMIC)
cpuflags = D3D11_CPU_ACCESS_WRITE;
else
cpuflags = (D3D11_CPU_ACCESS_FLAG)0;
D3D11_TEXTURE2D_DESC texdesc =
CD3D11_TEXTURE2D_DESC(fmt, width, height, slices, levels, bind, usage, cpuflags);
hr = D3D::device->CreateTexture2D(&texdesc, data, &pTexture);
if (FAILED(hr))
{
@ -172,22 +191,33 @@ UINT D3DTexture2D::Release()
}
D3DTexture2D::D3DTexture2D(ID3D11Texture2D* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT fmt,
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled)
: m_ref(1), m_tex(texptr), m_srv(nullptr), m_rtv(nullptr), m_dsv(nullptr), m_uav(nullptr)
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format,
bool multisampled, bool cube)
: m_ref(1), m_tex(texptr), m_srv(nullptr), m_rtv(nullptr), m_dsv(nullptr), m_uav(nullptr)
{
m_format = fmt;
D3D11_SRV_DIMENSION srv_dim = multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
D3D11_DSV_DIMENSION dsv_dim = multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
D3D11_RTV_DIMENSION rtv_dim = multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
D3D11_UAV_DIMENSION uav_dim = multisampled ? D3D11_UAV_DIMENSION_TEXTURE2DARRAY : D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
D3D11_SRV_DIMENSION srv_dim =
multisampled ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY :
(cube ? D3D11_SRV_DIMENSION_TEXTURECUBE : D3D11_SRV_DIMENSION_TEXTURE2DARRAY);
D3D11_DSV_DIMENSION dsv_dim =
multisampled ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
D3D11_RTV_DIMENSION rtv_dim =
multisampled ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
D3D11_UAV_DIMENSION uav_dim =
multisampled ? D3D11_UAV_DIMENSION_TEXTURE2DARRAY : D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(srv_dim, srv_format);
D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc = CD3D11_DEPTH_STENCIL_VIEW_DESC(dsv_dim, dsv_format);
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = CD3D11_RENDER_TARGET_VIEW_DESC(rtv_dim, rtv_format);
D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc = CD3D11_UNORDERED_ACCESS_VIEW_DESC(uav_dim, rtv_format);
if (bind & D3D11_BIND_SHADER_RESOURCE) D3D::device->CreateShaderResourceView(m_tex, &srv_desc, &m_srv);
if (bind & D3D11_BIND_RENDER_TARGET) D3D::device->CreateRenderTargetView(m_tex, &rtv_desc, &m_rtv);
if (bind & D3D11_BIND_DEPTH_STENCIL) D3D::device->CreateDepthStencilView(m_tex, &dsv_desc, &m_dsv);
if (bind & D3D11_BIND_UNORDERED_ACCESS) D3D::device->CreateUnorderedAccessView(m_tex, &uav_desc, &m_uav);
D3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc =
CD3D11_UNORDERED_ACCESS_VIEW_DESC(uav_dim, rtv_format);
if (bind & D3D11_BIND_SHADER_RESOURCE)
D3D::device->CreateShaderResourceView(m_tex, &srv_desc, &m_srv);
if (bind & D3D11_BIND_RENDER_TARGET)
D3D::device->CreateRenderTargetView(m_tex, &rtv_desc, &m_rtv);
if (bind & D3D11_BIND_DEPTH_STENCIL)
D3D::device->CreateDepthStencilView(m_tex, &dsv_desc, &m_dsv);
if (bind & D3D11_BIND_UNORDERED_ACCESS)
D3D::device->CreateUnorderedAccessView(m_tex, &uav_desc, &m_uav);
m_tex->AddRef();
}

View file

@ -28,7 +28,7 @@ public:
DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN,
bool multisampled = false);
bool multisampled = false, bool cube = false);
static D3DTexture2D* Create(
u32 width,
u32 height,

View file

@ -5,21 +5,21 @@
#include <algorithm>
#include <cstddef>
#include "Common/Assert.h"
#include "Common/Align.h"
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "VideoBackends/DX11/D3DBase.h"
#include "VideoBackends/DX11/D3DState.h"
#include "VideoBackends/DX11/D3DUtil.h"
#include "VideoBackends/DX11/D3DTexture.h"
#include "VideoBackends/DX11/D3DUtil.h"
#include "VideoBackends/DX11/DXTexture.h"
#include "VideoBackends/DX11/FramebufferManager.h"
#include "VideoBackends/DX11/GeometryShaderCache.h"
#include "VideoBackends/DX11/PixelShaderCache.h"
#include "VideoBackends/DX11/Render.h"
#include "VideoBackends/DX11/VertexShaderCache.h"
#include "VideoBackends/DX11/GeometryShaderCache.h"
#include "VideoCommon/ImageWrite.h"
#include "VideoCommon/TextureCacheBase.h"
@ -31,24 +31,23 @@ namespace
{
DXGI_FORMAT GetDXGIFormatForHostFormat(HostTextureFormat format)
{
static const DXGI_FORMAT HostTextureFormat_To_DXGIFORMAT[]
{
DXGI_FORMAT_UNKNOWN,//PC_TEX_FMT_NONE
DXGI_FORMAT_B8G8R8A8_UNORM,//PC_TEX_FMT_BGRA32
DXGI_FORMAT_R8G8B8A8_UNORM,//PC_TEX_FMT_RGBA32
DXGI_FORMAT_R8G8B8A8_UNORM,//PC_TEX_FMT_I4_AS_I8
DXGI_FORMAT_R8G8B8A8_UNORM,//PC_TEX_FMT_IA4_AS_IA8
DXGI_FORMAT_R8G8B8A8_UNORM,//PC_TEX_FMT_I8
DXGI_FORMAT_R8G8B8A8_UNORM,//PC_TEX_FMT_IA8
DXGI_FORMAT_B5G6R5_UNORM,//PC_TEX_FMT_RGB565
DXGI_FORMAT_BC1_UNORM,//PC_TEX_FMT_DXT1
DXGI_FORMAT_BC2_UNORM,//PC_TEX_FMT_DXT3
DXGI_FORMAT_BC3_UNORM,//PC_TEX_FMT_DXT5
DXGI_FORMAT_BC7_UNORM,//PC_TEX_FMT_BPTC
DXGI_FORMAT_R32_FLOAT,//PC_TEX_FMT_DEPTH_FLOAT
DXGI_FORMAT_R32_FLOAT,//PC_TEX_FMT_R_FLOAT
DXGI_FORMAT_R16G16B16A16_FLOAT,//PC_TEX_FMT_RGBA16_FLOAT
DXGI_FORMAT_R32G32B32A32_FLOAT,//PC_TEX_FMT_RGBA_FLOAT
static const DXGI_FORMAT HostTextureFormat_To_DXGIFORMAT[]{
DXGI_FORMAT_UNKNOWN, // PC_TEX_FMT_NONE
DXGI_FORMAT_B8G8R8A8_UNORM, // PC_TEX_FMT_BGRA32
DXGI_FORMAT_R8G8B8A8_UNORM, // PC_TEX_FMT_RGBA32
DXGI_FORMAT_R8G8B8A8_UNORM, // PC_TEX_FMT_I4_AS_I8
DXGI_FORMAT_R8G8B8A8_UNORM, // PC_TEX_FMT_IA4_AS_IA8
DXGI_FORMAT_R8G8B8A8_UNORM, // PC_TEX_FMT_I8
DXGI_FORMAT_R8G8B8A8_UNORM, // PC_TEX_FMT_IA8
DXGI_FORMAT_B5G6R5_UNORM, // PC_TEX_FMT_RGB565
DXGI_FORMAT_BC1_UNORM, // PC_TEX_FMT_DXT1
DXGI_FORMAT_BC2_UNORM, // PC_TEX_FMT_DXT3
DXGI_FORMAT_BC3_UNORM, // PC_TEX_FMT_DXT5
DXGI_FORMAT_BC7_UNORM, // PC_TEX_FMT_BPTC
DXGI_FORMAT_R32_FLOAT, // PC_TEX_FMT_DEPTH_FLOAT
DXGI_FORMAT_R32_FLOAT, // PC_TEX_FMT_R_FLOAT
DXGI_FORMAT_R16G16B16A16_FLOAT, // PC_TEX_FMT_RGBA16_FLOAT
DXGI_FORMAT_R32G32B32A32_FLOAT, // PC_TEX_FMT_RGBA_FLOAT
};
return HostTextureFormat_To_DXGIFORMAT[format];
@ -68,9 +67,8 @@ DXTexture::DXTexture(const TextureConfig& tex_config) : HostTexture(tex_config)
{
flags |= D3D11_BIND_UNORDERED_ACCESS;
}
m_texture = D3DTexture2D::Create(m_config.width, m_config.height,
(D3D11_BIND_FLAG)flags,
D3D11_USAGE_DEFAULT, format, 1, m_config.layers);
m_texture = D3DTexture2D::Create(m_config.width, m_config.height, (D3D11_BIND_FLAG)flags,
D3D11_USAGE_DEFAULT, format, 1, m_config.layers);
return;
}
bool bgrasupported = D3D::BGRATexturesSupported();
@ -84,7 +82,7 @@ DXTexture::DXTexture(const TextureConfig& tex_config) : HostTexture(tex_config)
convertrgb565 = true;
format = bgrasupported ? DXGI_FORMAT_B8G8R8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
}
usage = D3D11_USAGE_DEFAULT;
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
@ -93,16 +91,19 @@ DXTexture::DXTexture(const TextureConfig& tex_config) : HostTexture(tex_config)
usage = D3D11_USAGE_DYNAMIC;
cpu_access = D3D11_CPU_ACCESS_WRITE;
}
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(format,
m_config.width, m_config.height, m_config.layers, m_config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
ID3D11Texture2D *pTexture;
const D3D11_TEXTURE2D_DESC texdesc =
CD3D11_TEXTURE2D_DESC(format, m_config.width, m_config.height, m_config.layers,
m_config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access, 1, 0,
m_config.enviroment ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0);
ID3D11Texture2D* pTexture;
HRESULT hr = D3D::device->CreateTexture2D(&texdesc, NULL, &pTexture);
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
m_texture = new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE, format);
m_texture = new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE, format, DXGI_FORMAT_UNKNOWN,
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, m_config.enviroment);
// TODO: better debug names
D3D::SetDebugObjectName(m_texture->GetTex(), "a texture of the TextureCache");
D3D::SetDebugObjectName(m_texture->GetSRV(), "shader resource view of a texture of the TextureCache");
D3D::SetDebugObjectName(m_texture->GetSRV(),
"shader resource view of a texture of the TextureCache");
SAFE_RELEASE(pTexture);
}
@ -126,11 +127,8 @@ bool DXTexture::Save(const std::string& filename, u32 level)
// Create a staging/readback texture with the dimensions of the specified mip level.
u32 mip_width = std::max(m_config.width >> level, 1u);
u32 mip_height = std::max(m_config.height >> level, 1u);
CD3D11_TEXTURE2D_DESC staging_texture_desc(
m_texture->GetFormat(),
mip_width, mip_height, 1, 1, 0,
D3D11_USAGE_STAGING,
D3D11_CPU_ACCESS_READ);
CD3D11_TEXTURE2D_DESC staging_texture_desc(m_texture->GetFormat(), mip_width, mip_height, 1, 1, 0,
D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ);
ID3D11Texture2D* staging_texture;
HRESULT hr = D3D::device->CreateTexture2D(&staging_texture_desc, nullptr, &staging_texture);
@ -142,8 +140,8 @@ bool DXTexture::Save(const std::string& filename, u32 level)
// Copy the selected mip level to the staging texture.
CD3D11_BOX src_box(0, 0, 0, mip_width, mip_height, 1);
D3D::context->CopySubresourceRegion(staging_texture, 0, 0, 0, 0,
m_texture->GetTex(), D3D11CalcSubresource(level, 0, m_config.levels), &src_box);
D3D::context->CopySubresourceRegion(staging_texture, 0, 0, 0, 0, m_texture->GetTex(),
D3D11CalcSubresource(level, 0, m_config.levels), &src_box);
// Map the staging texture to client memory, and encode it as a .png image.
D3D11_MAPPED_SUBRESOURCE map;
@ -158,11 +156,13 @@ bool DXTexture::Save(const std::string& filename, u32 level)
bool encode_result = false;
if (this->compressed)
{
encode_result = TextureToDDS(reinterpret_cast<u8*>(map.pData), map.RowPitch, filename, mip_width, mip_height);
encode_result = TextureToDDS(reinterpret_cast<u8*>(map.pData), map.RowPitch, filename,
mip_width, mip_height);
}
else
{
encode_result = TextureToPng(reinterpret_cast<u8*>(map.pData), map.RowPitch, filename, mip_width, mip_height);
encode_result = TextureToPng(reinterpret_cast<u8*>(map.pData), map.RowPitch, filename,
mip_width, mip_height);
}
D3D::context->Unmap(staging_texture, 0);
staging_texture->Release();
@ -170,24 +170,17 @@ bool DXTexture::Save(const std::string& filename, u32 level)
return encode_result;
}
void DXTexture::CopyTexture(D3DTexture2D* source, D3DTexture2D* destination,
u32 srcwidth, u32 srcheight,
u32 dstwidth, u32 dstheight)
void DXTexture::CopyTexture(D3DTexture2D* source, D3DTexture2D* destination, u32 srcwidth,
u32 srcheight, u32 dstwidth, u32 dstheight)
{
if (source->GetFormat() == destination->GetFormat()
&& srcwidth == dstwidth && srcheight == dstheight)
if (source->GetFormat() == destination->GetFormat() && srcwidth == dstwidth &&
srcheight == dstheight)
{
D3D::context->CopyResource(
destination->GetTex(),
source->GetTex());
D3D::context->CopyResource(destination->GetTex(), source->GetTex());
return;
}
g_renderer->ResetAPIState(); // reset any game specific settings
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(
float(0),
float(0),
float(dstwidth),
float(dstheight));
g_renderer->ResetAPIState(); // reset any game specific settings
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(0), float(0), float(dstwidth), float(dstheight));
u64 texture_mask = D3D::stateman->UnsetTexture(destination->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &destination->GetRTV(), nullptr);
@ -198,31 +191,26 @@ void DXTexture::CopyTexture(D3DTexture2D* source, D3DTexture2D* destination,
srcRC.right = srcwidth;
srcRC.top = 0;
srcRC.bottom = srcheight;
D3D::drawShadedTexQuad(source->GetSRV(), &srcRC,
srcwidth, srcheight,
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
D3D::drawShadedTexQuad(
source->GetSRV(), &srcRC, srcwidth, srcheight, PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
D3D::context->OMSetRenderTargets(1,
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
D3D::stateman->SetTextureByMask(texture_mask, destination->GetSRV());
}
void DXTexture::CopyRectangle(D3DTexture2D* source, D3DTexture2D* destination,
const MathUtil::Rectangle<int>& srcrect, u32 srcwidth, u32 srcheight,
const MathUtil::Rectangle<int>& dstrect, u32 dstwidth, u32 dstheight)
const MathUtil::Rectangle<int>& srcrect, u32 srcwidth, u32 srcheight,
const MathUtil::Rectangle<int>& dstrect, u32 dstwidth, u32 dstheight)
{
g_renderer->ResetAPIState(); // reset any game specific settings
g_renderer->ResetAPIState(); // reset any game specific settings
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(
float(dstrect.left),
float(dstrect.top),
float(dstrect.GetWidth()),
float(dstrect.GetHeight()));
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(dstrect.left), float(dstrect.top),
float(dstrect.GetWidth()), float(dstrect.GetHeight()));
u64 texture_mask = D3D::stateman->UnsetTexture(destination->GetSRV());
D3D::stateman->Apply();
D3D::context->OMSetRenderTargets(1, &destination->GetRTV(), nullptr);
@ -233,43 +221,34 @@ void DXTexture::CopyRectangle(D3DTexture2D* source, D3DTexture2D* destination,
srcRC.right = srcrect.right;
srcRC.top = srcrect.top;
srcRC.bottom = srcrect.bottom;
D3D::drawShadedTexQuad(source->GetSRV(), &srcRC,
srcwidth, srcheight,
PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
D3D::drawShadedTexQuad(
source->GetSRV(), &srcRC, srcwidth, srcheight, PixelShaderCache::GetColorCopyProgram(false),
VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(),
GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0);
D3D::context->OMSetRenderTargets(1,
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(),
FramebufferManager::GetEFBDepthTexture()->GetDSV());
g_renderer->RestoreAPIState();
D3D::stateman->SetTextureByMask(texture_mask, destination->GetSRV());
}
void DXTexture::CopyRectangleFromTexture(const HostTexture* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
{
const DXTexture* srcentry = static_cast<const DXTexture*>(source);
if (this->GetRawTexIdentifier()->GetFormat() == srcentry->GetRawTexIdentifier()->GetFormat()
&& srcrect.GetWidth() == dstrect.GetWidth()
&& srcrect.GetHeight() == dstrect.GetHeight()
&& static_cast<UINT>(dstrect.GetWidth()) <= m_config.width
&& static_cast<UINT>(dstrect.GetHeight()) <= m_config.height
&& static_cast<UINT>(dstrect.GetWidth()) <= source->GetConfig().width
&& static_cast<UINT>(dstrect.GetHeight()) <= source->GetConfig().height)
if (this->GetRawTexIdentifier()->GetFormat() == srcentry->GetRawTexIdentifier()->GetFormat() &&
srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight() &&
static_cast<UINT>(dstrect.GetWidth()) <= m_config.width &&
static_cast<UINT>(dstrect.GetHeight()) <= m_config.height &&
static_cast<UINT>(dstrect.GetWidth()) <= source->GetConfig().width &&
static_cast<UINT>(dstrect.GetHeight()) <= source->GetConfig().height)
{
CD3D11_BOX src_box(srcrect.left, srcrect.top, 0, srcrect.right, srcrect.bottom, source->GetConfig().layers);
D3D::context->CopySubresourceRegion(
m_texture->GetTex(),
0,
dstrect.left,
dstrect.top,
0,
srcentry->m_texture->GetTex(),
0,
&src_box);
CD3D11_BOX src_box(srcrect.left, srcrect.top, 0, srcrect.right, srcrect.bottom,
source->GetConfig().layers);
D3D::context->CopySubresourceRegion(m_texture->GetTex(), 0, dstrect.left, dstrect.top, 0,
srcentry->m_texture->GetTex(), 0, &src_box);
return;
}
else if (!m_config.rendertarget)
@ -280,32 +259,23 @@ void DXTexture::CopyRectangleFromTexture(const HostTexture* source,
{
flags |= D3D11_BIND_UNORDERED_ACCESS;
}
D3DTexture2D* ptexture = D3DTexture2D::Create(m_config.width, m_config.height,
(D3D11_BIND_FLAG)flags,
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, m_config.layers);
D3DTexture2D* ptexture =
D3DTexture2D::Create(m_config.width, m_config.height, (D3D11_BIND_FLAG)flags,
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, m_config.layers);
CopyTexture(ptexture, m_texture, m_config.width, m_config.height, m_config.width, m_config.height);
CopyTexture(ptexture, m_texture, m_config.width, m_config.height, m_config.width,
m_config.height);
m_texture->Release();
m_texture = ptexture;
}
CopyRectangle(srcentry->m_texture, m_texture, srcrect, srcentry->m_config.width, srcentry->m_config.height, dstrect, m_config.width, m_config.height);
CopyRectangle(srcentry->m_texture, m_texture, srcrect, srcentry->m_config.width,
srcentry->m_config.height, dstrect, m_config.width, m_config.height);
}
void DXTexture::Load(const u8* src, u32 width, u32 height, u32 expanded_width, u32 level, u32 layer)
{
D3D::ReplaceTexture2D(
m_texture->GetTex(),
src,
width,
height,
expanded_width,
level,
layer,
m_config.levels,
usage,
m_texture->GetFormat(),
swap_rg,
convertrgb565);
D3D::ReplaceTexture2D(m_texture->GetTex(), src, width, height, expanded_width, level, layer,
m_config.levels, usage, m_texture->GetFormat(), swap_rg, convertrgb565);
}
} // namespace DX11

View file

@ -71,7 +71,7 @@ typedef struct _Nv_Stereo_Image_Header
// GX pipeline state
struct GXPipelineState
{
std::array<SamplerState, 8> samplers;
std::array<SamplerState, 16> samplers;
BlendingState blend;
DepthState zmode;
RasterizationState raster;
@ -762,7 +762,6 @@ void Renderer::ApplyState(bool bUseDstAlpha)
D3D::stateman->PushRasterizerState(s_gx_state_cache.Get(s_gx_state.raster));
for (u32 stage = 0; stage < static_cast<u32>(s_gx_state.samplers.size()); stage++)
D3D::stateman->SetSampler(stage, s_gx_state_cache.Get(s_gx_state.samplers[stage]));
D3D::BufferDescriptor vbuffer = VertexShaderCache::GetConstantBuffer();
D3D::BufferDescriptor pbuffer = PixelShaderCache::GetConstantBuffer();
ID3D11GeometryShader* geometry_shader = GeometryShaderCache::GetActiveShader();

View file

@ -73,6 +73,8 @@ enum BaseType
Unorm8
};
class D3DTexture2D;
class TextureEncoder
{

View file

@ -7,30 +7,30 @@
#include "Common/Logging/LogManager.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "VideoCommon/BPStructs.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/GeometryShaderManager.h"
#include "VideoCommon/TessellationShaderManager.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/TessellationShaderManager.h"
#include "VideoCommon/VertexLoaderManager.h"
#include "VideoCommon/VertexShaderManager.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "VideoCommon/VideoConfig.h"
#include "DolphinWX/Debugger/DebuggerPanel.h"
#include "VideoCommon/IndexGenerator.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "DolphinWX/Debugger/DebuggerPanel.h"
#include "DolphinWX/VideoConfigDiag.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoBackends/DX11/BoundingBox.h"
#include "VideoBackends/DX11/D3DUtil.h"
#include "VideoBackends/DX11/D3DBase.h"
#include "VideoBackends/DX11/D3DUtil.h"
#include "VideoBackends/DX11/GeometryShaderCache.h"
#include "VideoBackends/DX11/HullDomainShaderCache.h"
#include "VideoBackends/DX11/PerfQuery.h"
@ -40,12 +40,11 @@
#include "VideoBackends/DX11/VertexManager.h"
#include "VideoBackends/DX11/VertexShaderCache.h"
#include "VideoBackends/DX11/VideoBackend.h"
#include "Core/ConfigManager.h"
#include "VideoBackends/DX11/VideoBackend.h"
namespace DX11
{
unsigned int VideoBackend::PeekMessages()
{
MSG msg;
@ -72,7 +71,8 @@ std::string VideoBackend::GetDisplayName() const
void VideoBackend::InitBackendInfo()
{
HRESULT hr = DX11::D3D::LoadDXGI();
if (SUCCEEDED(hr)) hr = DX11::D3D::LoadD3D();
if (SUCCEEDED(hr))
hr = DX11::D3D::LoadD3D();
if (FAILED(hr))
{
DX11::D3D::UnloadDXGI();
@ -110,7 +110,8 @@ void VideoBackend::InitBackendInfo()
// adapters
g_Config.backend_info.Adapters.clear();
g_Config.backend_info.AAModes.clear();
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != DXGI_ERROR_NOT_FOUND)
while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) !=
DXGI_ERROR_NOT_FOUND)
{
const size_t adapter_index = g_Config.backend_info.Adapters.size();
@ -140,7 +141,8 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsSSAA = shader_model_5_supported;
g_Config.backend_info.bSupportsGPUTextureDecoding = shader_model_5_supported;
g_Config.backend_info.bSupportsComputeTextureEncoding = shader_model_5_supported;
g_Config.backend_info.MaxTextureSize = DX11::D3D::GetMaxTextureSize(DX11::D3D::GetFeatureLevel(ad));
g_Config.backend_info.MaxTextureSize =
DX11::D3D::GetMaxTextureSize(DX11::D3D::GetFeatureLevel(ad));
}
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
@ -153,7 +155,7 @@ void VideoBackend::InitBackendInfo()
DX11::D3D::UnloadD3D();
}
bool VideoBackend::Initialize(void *window_handle)
bool VideoBackend::Initialize(void* window_handle)
{
if (window_handle == nullptr)
return false;
@ -167,10 +169,10 @@ void VideoBackend::Video_Prepare()
{
// internal interfaces
g_renderer = std::make_unique<Renderer>(m_window_handle);
g_renderer->Init();
g_texture_cache = std::make_unique<TextureCache>();
g_vertex_manager = std::make_unique<VertexManager>();
g_perf_query = std::make_unique<PerfQuery>();
g_renderer->Init();
VertexShaderCache::Init();
PixelShaderCache::Init();
GeometryShaderCache::Init();
@ -202,4 +204,4 @@ void VideoBackend::Video_Cleanup()
CleanupShared();
}
}
} // namespace DX11

View file

@ -131,7 +131,7 @@ void OGLTexture::SetFormat()
gl_type = GL_FLOAT;
compressed = false;
break;
default:
default:
break;
}
if (compressed && m_config.rendertarget)
@ -149,14 +149,23 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : HostTexture(tex_config
glGenTextures(1, &m_texId);
glActiveTexture(GL_TEXTURE9);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
glBindTexture(tex_config.enviroment ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY, m_texId);
glTexParameteri(tex_config.enviroment ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY,
GL_TEXTURE_MAX_LEVEL, m_config.levels - 1);
SetFormat();
if (g_ogl_config.bSupportsTextureStorage)
{
glTexStorage3D(GL_TEXTURE_2D_ARRAY, m_config.levels, gl_siformat, m_config.width, m_config.height,
m_config.layers);
if (tex_config.enviroment)
{
glTexStorage2D(GL_TEXTURE_CUBE_MAP, m_config.levels, gl_siformat, m_config.width,
m_config.height);
}
else
{
glTexStorage3D(GL_TEXTURE_2D_ARRAY, m_config.levels, gl_siformat, m_config.width,
m_config.height, m_config.layers);
}
}
if (m_config.rendertarget)
@ -165,15 +174,17 @@ OGLTexture::OGLTexture(const TextureConfig& tex_config) : HostTexture(tex_config
{
for (u32 level = 0; level < m_config.levels; level++)
{
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_format,
std::max(m_config.width >> level, 1u),
std::max(m_config.height >> level, 1u),
m_config.layers, 0, gl_iformat, gl_type, nullptr);
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_format, std::max(m_config.width >> level, 1u),
std::max(m_config.height >> level, 1u), m_config.layers, 0, gl_iformat,
gl_type, nullptr);
}
}
glGenFramebuffers(1, &m_framebuffer);
FramebufferManager::SetFramebuffer(m_framebuffer);
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, (gl_iformat == GL_DEPTH_COMPONENT) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, m_texId, 0);
FramebufferManager::FramebufferTexture(
GL_FRAMEBUFFER,
(gl_iformat == GL_DEPTH_COMPONENT) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D_ARRAY, m_texId, 0);
}
SetStage();
}
@ -211,7 +222,7 @@ void OGLTexture::Bind(u32 stage)
if (s_Textures[stage] != m_texId || !g_ActiveConfig.backend_info.bSupportsBindingLayout)
{
glActiveTexture(GL_TEXTURE0 + stage);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
glBindTexture(m_config.enviroment ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY, m_texId);
s_Textures[stage] = m_texId;
}
}
@ -242,17 +253,16 @@ bool OGLTexture::Save(const std::string& filename, u32 level)
}
void OGLTexture::CopyRectangleFromTexture(const HostTexture* source,
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
const MathUtil::Rectangle<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
{
const OGLTexture* srcentry = static_cast<const OGLTexture*>(source);
if (this->gl_format == srcentry->gl_format
&& srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight() &&
g_ogl_config.bSupportsCopySubImage)
if (this->gl_format == srcentry->gl_format && srcrect.GetWidth() == dstrect.GetWidth() &&
srcrect.GetHeight() == dstrect.GetHeight() && g_ogl_config.bSupportsCopySubImage)
{
glCopyImageSubData(srcentry->m_texId, GL_TEXTURE_2D_ARRAY, 0, srcrect.left, srcrect.top, 0,
m_texId, GL_TEXTURE_2D_ARRAY, 0, dstrect.left, dstrect.top, 0,
dstrect.GetWidth(), dstrect.GetHeight(), srcentry->m_config.layers);
m_texId, GL_TEXTURE_2D_ARRAY, 0, dstrect.left, dstrect.top, 0,
dstrect.GetWidth(), dstrect.GetHeight(), srcentry->m_config.layers);
return;
}
else if (!m_framebuffer)
@ -261,7 +271,7 @@ void OGLTexture::CopyRectangleFromTexture(const HostTexture* source,
glGenFramebuffers(1, &m_framebuffer);
FramebufferManager::SetFramebuffer(m_framebuffer);
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D_ARRAY, m_texId, 0);
GL_TEXTURE_2D_ARRAY, m_texId, 0);
}
g_renderer->ResetAPIState();
FramebufferManager::SetFramebuffer(m_framebuffer);
@ -270,18 +280,19 @@ void OGLTexture::CopyRectangleFromTexture(const HostTexture* source,
g_sampler_cache->BindLinearSampler(g_ActiveConfig.backend_info.bSupportsBindingLayout ? 9 : 0);
glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight());
static_cast<OGL::TextureCache*>(g_texture_cache.get())->GetColorCopyProgram().Bind();
glUniform4f(static_cast<OGL::TextureCache*>(g_texture_cache.get())->GetColorCopyPositionUniform(), float(srcrect.left),
float(srcrect.top), float(srcrect.GetWidth()), float(srcrect.GetHeight()));
glUniform4f(static_cast<OGL::TextureCache*>(g_texture_cache.get())->GetColorCopyPositionUniform(),
float(srcrect.left), float(srcrect.top), float(srcrect.GetWidth()),
float(srcrect.GetHeight()));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
FramebufferManager::SetFramebuffer(0);
g_renderer->RestoreAPIState();
}
void OGLTexture::Load(const u8* src, u32 width, u32 height,
u32 expanded_width, u32 level, u32 layer)
void OGLTexture::Load(const u8* src, u32 width, u32 height, u32 expanded_width, u32 level,
u32 layer)
{
glActiveTexture(GL_TEXTURE9);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId);
glBindTexture(m_config.enviroment ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY, m_texId);
u32 blocksize = (m_config.pcformat == PC_TEX_FMT_DXT1) ? 8u : 16u;
switch (m_config.pcformat)
@ -289,8 +300,7 @@ void OGLTexture::Load(const u8* src, u32 width, u32 height,
case PC_TEX_FMT_DXT1:
case PC_TEX_FMT_DXT3:
case PC_TEX_FMT_DXT5:
case PC_TEX_FMT_BPTC:
{
case PC_TEX_FMT_BPTC: {
if (expanded_width != width)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@ -300,16 +310,36 @@ void OGLTexture::Load(const u8* src, u32 width, u32 height,
glPixelStorei(GL_UNPACK_COMPRESSED_BLOCK_SIZE, blocksize);
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
}
if (g_ogl_config.bSupportsTextureStorage)
if (m_config.enviroment)
{
glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, layer,
width, height, 1, gl_format, ((width + 3) >> 2) * ((height + 3) >> 2) * blocksize, src);
if (g_ogl_config.bSupportsTextureStorage)
{
glCompressedTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, level, 0, 0, width,
height, gl_format,
((width + 3) >> 2) * ((height + 3) >> 2) * blocksize, src);
}
else
{
glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, level, gl_iformat, width,
height, 0, ((width + 3) >> 2) * ((height + 3) >> 2) * blocksize,
src);
}
}
else
{
glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_format,
width, height, 1, 0, ((width + 3) >> 2) * ((height + 3) >> 2) * blocksize, src);
if (g_ogl_config.bSupportsTextureStorage)
{
glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, layer, width, height, 1,
gl_format, ((width + 3) >> 2) * ((height + 3) >> 2) * blocksize,
src);
}
else
{
glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_format, width, height, 1, 0,
((width + 3) >> 2) * ((height + 3) >> 2) * blocksize, src);
}
}
if (expanded_width != width)
{
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@ -320,19 +350,34 @@ void OGLTexture::Load(const u8* src, u32 width, u32 height,
}
}
break;
default:
{
default: {
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
if (g_ogl_config.bSupportsTextureStorage)
if (m_config.enviroment)
{
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, layer, width, height, 1, gl_format,
gl_type, src);
if (g_ogl_config.bSupportsTextureStorage)
{
glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, level, 0, 0, width, height,
gl_format, gl_type, src);
}
else
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer, level, gl_iformat, width, height, 0,
gl_format, gl_type, src);
}
}
else
{
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_iformat, width, height, 1, 0, gl_format,
gl_type, src);
if (g_ogl_config.bSupportsTextureStorage)
{
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, 0, 0, layer, width, height, 1, gl_format,
gl_type, src);
}
else
{
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_iformat, width, height, 1, 0, gl_format,
gl_type, src);
}
}
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@ -342,9 +387,7 @@ void OGLTexture::Load(const u8* src, u32 width, u32 height,
SetStage();
}
void OGLTexture::DisableStage(u32 stage)
{
}
void OGLTexture::DisableStage(u32 stage) {}
void OGLTexture::SetStage()
{

View file

@ -36,7 +36,7 @@ private:
static void SetParameters(GLuint sampler_id, const SamplerState& params);
std::map<SamplerState, GLuint> m_cache;
std::array<std::pair<SamplerState, GLuint>, 8> m_active_samplers{};
std::array<std::pair<SamplerState, GLuint>, 9> m_active_samplers{};
GLuint m_point_sampler;
GLuint m_linear_sampler;

View file

@ -86,7 +86,7 @@ enum UNIFORM_BUFFER_DESCRIPTOR_SET_BINDING
constexpr size_t MAX_VERTEX_ATTRIBUTES = 16;
// Number of pixel shader texture slots
constexpr size_t NUM_PIXEL_SHADER_SAMPLERS = 8;
constexpr size_t NUM_PIXEL_SHADER_SAMPLERS = 9;
// Total number of binding points in the pipeline layout
constexpr size_t TOTAL_PIPELINE_BINDING_POINTS =

View file

@ -12,13 +12,12 @@
namespace Vulkan
{
Texture2D::Texture2D(u32 width, u32 height, u32 levels, u32 layers, VkFormat format,
VkSampleCountFlagBits samples, VkImageViewType view_type, VkImage image,
VkDeviceMemory device_memory, VkImageView view, VkImageUsageFlags usage)
: m_width(width), m_height(height), m_levels(levels), m_layers(layers), m_format(format),
m_samples(samples), m_view_type(view_type), m_image(image), m_device_memory(device_memory),
m_view(view), m_usage(usage), m_framebuffer(nullptr)
VkSampleCountFlagBits samples, VkImageViewType view_type, VkImage image,
VkDeviceMemory device_memory, VkImageView view, VkImageUsageFlags usage)
: m_width(width), m_height(height), m_levels(levels), m_layers(layers), m_format(format),
m_samples(samples), m_view_type(view_type), m_image(image), m_device_memory(device_memory),
m_view(view), m_usage(usage), m_framebuffer(nullptr)
{
}
void Texture2D::AddFramebuffer(VkRenderPass renderpass, bool clear)
@ -26,20 +25,20 @@ void Texture2D::AddFramebuffer(VkRenderPass renderpass, bool clear)
VkFramebuffer framebuffer = VK_NULL_HANDLE;
if (m_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT && renderpass != VK_NULL_HANDLE)
{
VkImageView framebuffer_attachments[] = { m_view };
VkImageView framebuffer_attachments[] = {m_view};
VkFramebufferCreateInfo framebuffer_info = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
renderpass,
static_cast<u32>(ArraySize(framebuffer_attachments)),
framebuffer_attachments,
m_width,
m_height,
m_layers };
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
renderpass,
static_cast<u32>(ArraySize(framebuffer_attachments)),
framebuffer_attachments,
m_width,
m_height,
m_layers};
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr,
&framebuffer);
&framebuffer);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer failed: ");
@ -49,13 +48,12 @@ void Texture2D::AddFramebuffer(VkRenderPass renderpass, bool clear)
if (clear)
{
// Clear render targets before use to prevent reading uninitialized memory.
VkClearColorValue clear_value = { { 0.0f, 0.0f, 0.0f, 1.0f } };
VkImageSubresourceRange clear_range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, m_levels, 0,
m_layers };
VkClearColorValue clear_value = {{0.0f, 0.0f, 0.0f, 1.0f}};
VkImageSubresourceRange clear_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, m_levels, 0, m_layers};
TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), m_image,
m_layout, &clear_value, 1, &clear_range);
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentInitCommandBuffer(), m_image, m_layout,
&clear_value, 1, &clear_range);
}
}
}
@ -76,13 +74,13 @@ Texture2D::~Texture2D()
}
std::unique_ptr<Texture2D> Texture2D::Create(u32 width, u32 height, u32 levels, u32 layers,
VkFormat format, VkSampleCountFlagBits samples,
VkImageViewType view_type, VkImageTiling tiling,
VkImageUsageFlags usage)
VkFormat format, VkSampleCountFlagBits samples,
VkImageViewType view_type, VkImageTiling tiling,
VkImageUsageFlags usage, VkImageCreateFlags flags)
{
VkImageCreateInfo image_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
VkImageCreateInfo image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
nullptr,
0,
flags,
VK_IMAGE_TYPE_2D,
format,
{width, height, 1},
@ -94,7 +92,7 @@ std::unique_ptr<Texture2D> Texture2D::Create(u32 width, u32 height, u32 levels,
VK_SHARING_MODE_EXCLUSIVE,
0,
nullptr,
VK_IMAGE_LAYOUT_UNDEFINED };
VK_IMAGE_LAYOUT_UNDEFINED};
VkImage image = VK_NULL_HANDLE;
VkResult res = vkCreateImage(g_vulkan_context->GetDevice(), &image_info, nullptr, &image);
@ -111,7 +109,7 @@ std::unique_ptr<Texture2D> Texture2D::Create(u32 width, u32 height, u32 levels,
VkMemoryAllocateInfo memory_info = {
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, nullptr, memory_requirements.size,
g_vulkan_context->GetMemoryType(memory_requirements.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) };
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)};
VkDeviceMemory device_memory;
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_info, nullptr, &device_memory);
@ -142,7 +140,7 @@ std::unique_ptr<Texture2D> Texture2D::Create(u32 width, u32 height, u32 levels,
VK_COMPONENT_SWIZZLE_IDENTITY},
{Util::IsDepthFormat(format) ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
0, levels, 0, layers} };
0, levels, 0, layers}};
VkImageView view = VK_NULL_HANDLE;
res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view);
@ -154,14 +152,13 @@ std::unique_ptr<Texture2D> Texture2D::Create(u32 width, u32 height, u32 levels,
return nullptr;
}
return std::make_unique<Texture2D>(width, height, levels, layers, format, samples, view_type,
image, device_memory, view, usage);
image, device_memory, view, usage);
}
std::unique_ptr<Texture2D> Texture2D::CreateFromExistingImage(u32 width, u32 height, u32 levels,
u32 layers, VkFormat format,
VkSampleCountFlagBits samples,
VkImageViewType view_type,
VkImage existing_image, VkImageUsageFlags usage)
std::unique_ptr<Texture2D>
Texture2D::CreateFromExistingImage(u32 width, u32 height, u32 levels, u32 layers, VkFormat format,
VkSampleCountFlagBits samples, VkImageViewType view_type,
VkImage existing_image, VkImageUsageFlags usage)
{
// Only need to create the image view, this is mainly for swap chains.
VkImageViewCreateInfo view_info = {
@ -175,7 +172,7 @@ std::unique_ptr<Texture2D> Texture2D::CreateFromExistingImage(u32 width, u32 hei
VK_COMPONENT_SWIZZLE_IDENTITY},
{Util::IsDepthFormat(format) ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
0, levels, 0, layers} };
0, levels, 0, layers}};
// Memory is managed by the owner of the image.
VkDeviceMemory memory = VK_NULL_HANDLE;
@ -185,9 +182,9 @@ std::unique_ptr<Texture2D> Texture2D::CreateFromExistingImage(u32 width, u32 hei
{
LOG_VULKAN_ERROR(res, "vkCreateImageView failed: ");
return nullptr;
}
}
return std::make_unique<Texture2D>(width, height, levels, layers, format, samples, view_type,
existing_image, memory, view, usage);
existing_image, memory, view, usage);
}
void Texture2D::OverrideImageLayout(VkImageLayout new_layout)
@ -201,18 +198,18 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout
return;
VkImageMemoryBarrier barrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
nullptr, // const void* pNext
0, // VkAccessFlags srcAccessMask
0, // VkAccessFlags dstAccessMask
m_layout, // VkImageLayout oldLayout
new_layout, // VkImageLayout newLayout
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image
{ static_cast<VkImageAspectFlags>(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT :
VK_IMAGE_ASPECT_COLOR_BIT),
0, m_levels, 0, m_layers } // VkImageSubresourceRange subresourceRange
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
nullptr, // const void* pNext
0, // VkAccessFlags srcAccessMask
0, // VkAccessFlags dstAccessMask
m_layout, // VkImageLayout oldLayout
new_layout, // VkImageLayout newLayout
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image
{static_cast<VkImageAspectFlags>(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT :
VK_IMAGE_ASPECT_COLOR_BIT),
0, m_levels, 0, m_layers} // VkImageSubresourceRange subresourceRange
};
// srcStageMask -> Stages that must complete before the barrier
@ -235,14 +232,14 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Image was being used as a color attachment, so ensure all writes have completed.
barrier.srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Image was being used as a depthstencil attachment, so ensure all writes have completed.
barrier.srcAccessMask =
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
@ -278,13 +275,13 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
barrier.dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
barrier.dstAccessMask =
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;
@ -336,7 +333,7 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout
m_compute_layout = ComputeImageLayout::Undefined;
vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
&barrier);
&barrier);
m_layout = new_layout;
}
@ -348,18 +345,18 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, ComputeImageL
return;
VkImageMemoryBarrier barrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
nullptr, // const void* pNext
0, // VkAccessFlags srcAccessMask
0, // VkAccessFlags dstAccessMask
m_layout, // VkImageLayout oldLayout
VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image
{ static_cast<VkImageAspectFlags>(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT :
VK_IMAGE_ASPECT_COLOR_BIT),
0, m_levels, 0, m_layers } // VkImageSubresourceRange subresourceRange
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
nullptr, // const void* pNext
0, // VkAccessFlags srcAccessMask
0, // VkAccessFlags dstAccessMask
m_layout, // VkImageLayout oldLayout
VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image
{static_cast<VkImageAspectFlags>(Util::IsDepthFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT :
VK_IMAGE_ASPECT_COLOR_BIT),
0, m_levels, 0, m_layers} // VkImageSubresourceRange subresourceRange
};
VkPipelineStageFlags srcStageMask, dstStageMask;
@ -380,14 +377,14 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, ComputeImageL
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Image was being used as a color attachment, so ensure all writes have completed.
barrier.srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Image was being used as a depthstencil attachment, so ensure all writes have completed.
barrier.srcAccessMask =
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
@ -440,6 +437,6 @@ void Texture2D::TransitionToLayout(VkCommandBuffer command_buffer, ComputeImageL
m_compute_layout = new_layout;
vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
&barrier);
&barrier);
}
} // namespace Vulkan

View file

@ -35,7 +35,7 @@ public:
static std::unique_ptr<Texture2D> Create(u32 width, u32 height, u32 levels, u32 layers,
VkFormat format, VkSampleCountFlagBits samples,
VkImageViewType view_type, VkImageTiling tiling,
VkImageUsageFlags usage);
VkImageUsageFlags usage, VkImageCreateFlags flags = 0);
static std::unique_ptr<Texture2D> CreateFromExistingImage(u32 width, u32 height, u32 levels,
u32 layers, VkFormat format,

View file

@ -48,8 +48,10 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
}
}
auto texture = Texture2D::Create(tex_config.width, tex_config.height, tex_config.levels,
tex_config.layers, vk_format, VK_SAMPLE_COUNT_1_BIT,
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage);
tex_config.layers, vk_format, VK_SAMPLE_COUNT_1_BIT,
tex_config.enviroment ? VK_IMAGE_VIEW_TYPE_CUBE :
VK_IMAGE_VIEW_TYPE_2D_ARRAY,
VK_IMAGE_TILING_OPTIMAL, usage, tex_config.enviroment ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0);
if (!texture)
{

View file

@ -60,12 +60,24 @@ enum MapType
};
static const std::string s_maps_tags[] = {
std::string(""), std::string(".mat"), std::string(".lum"),
std::string(".nrm"), std::string(".bump"), std::string(".spec"),
enum EnvType
{
positiveX = 0,
negativeX = 1,
positiveY = 2,
negativeY = 3,
positiveZ = 4,
negativeZ = 5
};
static const std::string s_maps_tags[] = {std::string(""), std::string(".mat"),
std::string(".lum"), std::string(".nrm"),
std::string(".bump"), std::string(".spec")};
static const std::string s_env_tags[] = {std::string(".px"), std::string(".nx"),
std::string(".py"), std::string(".ny"),
std::string(".pz"), std::string(".nz")};
struct HiresTextureCacheItem
{
bool has_arbitrary_mips;
@ -77,10 +89,25 @@ struct HiresTextureCacheItem
}
};
typedef std::unordered_map<std::string, HiresTextureCacheItem> HiresTextureCache;
static HiresTextureCache s_textureMap;
struct EnvTextureCacheItem
{
bool has_arbitrary_mips;
std::array<std::vector<hires_mip_level>, EnvType::negativeZ + 1> maps;
EnvTextureCacheItem(size_t minsize) : has_arbitrary_mips(false)
{
maps[EnvType::positiveX].resize(minsize);
}
};
typedef std::unordered_map<std::string, HiresTextureCacheItem> HiresTextureCache;
typedef std::unordered_map<std::string, EnvTextureCacheItem> EnvTextureCache;
static HiresTextureCache s_textureMap;
static EnvTextureCache s_enviromentMap;
typedef std::unordered_map<std::string, std::shared_ptr<HiresTexture>> TextureCache;
static TextureCache s_textureCache;
static TextureCache s_enviromentCache;
static std::unordered_map<std::string, std::shared_ptr<HiresTexture>> s_textureCache;
static std::mutex s_textureCacheMutex;
static Common::Flag s_textureCacheAbortLoading;
@ -89,6 +116,8 @@ static size_t max_mem = 0;
static std::thread s_prefetcher;
static const std::string s_format_prefix = "tex1_";
static const std::string s_enviroment_prefix = "env_";
HiresTexture::HiresTexture()
: m_format(PC_TEX_FMT_NONE), m_height(0), m_levels(0), m_nrm_levels(0), m_lum_levels(0),
m_cached_data(nullptr), m_cached_data_size(0)
@ -112,8 +141,8 @@ void HiresTexture::Shutdown()
s_textureCacheAbortLoading.Set();
s_prefetcher.join();
}
s_textureMap.clear();
s_enviromentMap.clear();
s_textureCache.clear();
}
@ -128,6 +157,124 @@ std::string HiresTexture::GetTextureDirectory(const std::string& game_id)
return texture_directory;
}
static const std::string ddscode = ".dds";
static const std::string cddscode = ".DDS";
static const std::string miptag = "mip";
void HiresTexture::ProccessEnviroment(const std::string& fileitem, std::string& filename,
const std::string& extension)
{
size_t map_index = 0;
for (size_t tag = 0; tag <= EnvType::negativeZ; tag++)
{
if (StringEndsWith(filename, s_env_tags[tag]))
{
map_index = tag;
filename = filename.substr(0, filename.size() - s_env_tags[tag].size());
break;
}
}
const bool is_compressed = extension.compare(ddscode) == 0 || extension.compare(cddscode) == 0;
hires_mip_level mip_level_detail(fileitem, extension, is_compressed);
u32 level = 0;
size_t idx = filename.find_last_of('_');
std::string miplevel = filename.substr(idx + 1, std::string::npos);
if (miplevel.substr(0, miptag.length()) == miptag)
{
sscanf(miplevel.substr(3, std::string::npos).c_str(), "%i", &level);
filename = filename.substr(0, idx);
}
EnvTextureCache::iterator iter = s_enviromentMap.find(filename);
u32 min_item_size = level + 1;
if (iter == s_enviromentMap.end())
{
EnvTextureCacheItem item(min_item_size);
item.maps[map_index].resize(min_item_size);
std::vector<hires_mip_level>& dst = item.maps[map_index];
dst[level] = mip_level_detail;
s_enviromentMap.emplace(filename, item);
}
else
{
std::vector<hires_mip_level>& dst = iter->second.maps[map_index];
if (dst.size() < min_item_size)
{
dst.resize(min_item_size);
}
dst[level] = mip_level_detail;
}
}
void HiresTexture::ProccessTexture(const std::string& fileitem, std::string& filename,
const std::string& extension, const bool BuildMaterialMaps)
{
size_t map_index = 0;
size_t max_type = BuildMaterialMaps ? MapType::specular : MapType::normal;
bool arbitrary_mips = false;
for (size_t tag = 1; tag <= MapType::specular; tag++)
{
if (StringEndsWith(filename, s_maps_tags[tag]))
{
map_index = tag;
filename = filename.substr(0, filename.size() - s_maps_tags[tag].size());
break;
}
}
if (map_index > max_type)
{
return;
}
if (BuildMaterialMaps && map_index == MapType::material)
{
return;
}
else if (!BuildMaterialMaps && map_index == MapType::color)
{
const size_t arb_index = filename.rfind("_arb");
arbitrary_mips = arb_index != std::string::npos;
if (arbitrary_mips)
filename.erase(arb_index, 4);
}
const bool is_compressed = extension.compare(ddscode) == 0 || extension.compare(cddscode) == 0;
hires_mip_level mip_level_detail(fileitem, extension, is_compressed);
u32 level = 0;
size_t idx = filename.find_last_of('_');
std::string miplevel = filename.substr(idx + 1, std::string::npos);
if (miplevel.substr(0, miptag.length()) == miptag)
{
sscanf(miplevel.substr(3, std::string::npos).c_str(), "%i", &level);
filename = filename.substr(0, idx);
}
HiresTextureCache::iterator iter = s_textureMap.find(filename);
u32 min_item_size = level + 1;
if (iter == s_textureMap.end())
{
HiresTextureCacheItem item(min_item_size);
if (arbitrary_mips)
{
item.has_arbitrary_mips = true;
}
item.maps[map_index].resize(min_item_size);
std::vector<hires_mip_level>& dst = item.maps[map_index];
dst[level] = mip_level_detail;
s_textureMap.emplace(filename, item);
}
else
{
std::vector<hires_mip_level>& dst = iter->second.maps[map_index];
if (arbitrary_mips)
{
iter->second.has_arbitrary_mips = true;
}
if (dst.size() < min_item_size)
{
dst.resize(min_item_size);
}
dst[level] = mip_level_detail;
}
}
void HiresTexture::Update()
{
bool BuildMaterialMaps = g_ActiveConfig.bHiresMaterialMapsBuild;
@ -140,7 +287,9 @@ void HiresTexture::Update()
if (!g_ActiveConfig.bHiresTextures)
{
s_textureMap.clear();
s_enviromentMap.clear();
s_textureCache.clear();
s_enviromentCache.clear();
size_sum.store(0);
return;
}
@ -148,15 +297,15 @@ void HiresTexture::Update()
if (!g_ActiveConfig.bCacheHiresTextures)
{
s_textureCache.clear();
s_enviromentCache.clear();
size_sum.store(0);
}
s_textureMap.clear();
s_enviromentMap.clear();
const std::string& game_id = SConfig::GetInstance().GetGameID();
const std::string texture_directory = GetTextureDirectory(game_id);
std::string ddscode(".dds");
std::string cddscode(".DDS");
const std::string resource_directory = File::GetSysDirectory() + RESOURCES_DIR DIR_SEP;
std::vector<std::string> Extensions;
Extensions.push_back(".png");
if (!BuildMaterialMaps)
@ -164,84 +313,41 @@ void HiresTexture::Update()
Extensions.push_back(".dds");
}
std::vector<std::string> Resourcefilenames =
Common::DoFileSearch({resource_directory}, Extensions, /*recursive*/ true);
for (const std::string& fileitem : Resourcefilenames)
{
std::string filename;
std::string extension;
SplitPath(fileitem, nullptr, &filename, &extension);
if (filename.starts_with(s_format_prefix))
{
ProccessTexture(fileitem, filename, extension, BuildMaterialMaps);
}
else if (filename.starts_with(s_enviroment_prefix))
{
filename = filename.substr(s_enviroment_prefix.length());
ProccessEnviroment(fileitem, filename, extension);
}
}
std::vector<std::string> filenames =
Common::DoFileSearch({texture_directory}, Extensions, /*recursive*/ true);
const std::string miptag = "mip";
for (const std::string& fileitem : filenames)
{
std::string filename;
std::string Extension;
SplitPath(fileitem, nullptr, &filename, &Extension);
if (filename.substr(0, s_format_prefix.length()) != s_format_prefix)
std::string extension;
SplitPath(fileitem, nullptr, &filename, &extension);
if (filename.starts_with(s_format_prefix))
{
// Discard wrong files
continue;
ProccessTexture(fileitem, filename, extension, BuildMaterialMaps);
}
size_t map_index = 0;
size_t max_type = BuildMaterialMaps ? MapType::specular : MapType::normal;
bool arbitrary_mips = false;
for (size_t tag = 1; tag <= MapType::specular; tag++)
else if (filename.starts_with(s_enviroment_prefix))
{
if (StringEndsWith(filename, s_maps_tags[tag]))
{
map_index = tag;
filename = filename.substr(0, filename.size() - s_maps_tags[tag].size());
break;
}
}
if (map_index > max_type)
{
continue;
}
if (BuildMaterialMaps && map_index == MapType::material)
{
continue;
}
else if (!BuildMaterialMaps && map_index == MapType::color)
{
const size_t arb_index = filename.rfind("_arb");
arbitrary_mips = arb_index != std::string::npos;
if (arbitrary_mips)
filename.erase(arb_index, 4);
}
const bool is_compressed = Extension.compare(ddscode) == 0 || Extension.compare(cddscode) == 0;
hires_mip_level mip_level_detail(fileitem, Extension, is_compressed);
u32 level = 0;
size_t idx = filename.find_last_of('_');
std::string miplevel = filename.substr(idx + 1, std::string::npos);
if (miplevel.substr(0, miptag.length()) == miptag)
{
sscanf(miplevel.substr(3, std::string::npos).c_str(), "%i", &level);
filename = filename.substr(0, idx);
}
HiresTextureCache::iterator iter = s_textureMap.find(filename);
u32 min_item_size = level + 1;
if (iter == s_textureMap.end())
{
HiresTextureCacheItem item(min_item_size);
if (arbitrary_mips)
{
item.has_arbitrary_mips = true;
}
item.maps[map_index].resize(min_item_size);
std::vector<hires_mip_level>& dst = item.maps[map_index];
dst[level] = mip_level_detail;
s_textureMap.emplace(filename, item);
}
else
{
std::vector<hires_mip_level>& dst = iter->second.maps[map_index];
if (arbitrary_mips)
{
iter->second.has_arbitrary_mips = true;
}
if (dst.size() < min_item_size)
{
dst.resize(min_item_size);
}
dst[level] = mip_level_detail;
filename = filename.substr(s_enviroment_prefix.length());
ProccessEnviroment(fileitem, filename, extension);
}
}
@ -261,6 +367,20 @@ void HiresTexture::Update()
iter++;
}
}
// remove cached but deleted enviroment textures
auto iterenv = s_enviromentCache.begin();
while (iterenv != s_enviromentCache.end())
{
if (s_enviromentMap.find(iterenv->first) == s_enviromentMap.end())
{
size_sum.fetch_sub(iterenv->second->m_cached_data_size);
iterenv = s_enviromentCache.erase(iterenv);
}
else
{
iterenv++;
}
}
s_textureCacheAbortLoading.Clear();
s_prefetcher = std::thread(Prefetch);
if (g_ActiveConfig.bWaitForCacheHiresTextures && s_prefetcher.joinable())
@ -273,7 +393,7 @@ void HiresTexture::Update()
void HiresTexture::Prefetch()
{
Common::SetCurrentThreadName("Prefetcher");
const size_t total = s_textureMap.size();
const size_t total = s_textureMap.size() + s_enviromentMap.size();
size_t count = 0;
size_t notification = 10;
u32 starttime = Common::Timer::GetTimeMs();
@ -287,8 +407,8 @@ void HiresTexture::Prefetch()
if (iter == s_textureCache.end())
{
lk.unlock();
HiresTexture* ptr =
Load(base_filename, [](size_t requested_size) { return new u8[requested_size]; }, true);
HiresTexture* ptr = Load(
base_filename, [](size_t requested_size) { return new u8[requested_size]; }, true);
lk.lock();
if (ptr != nullptr)
{
@ -340,6 +460,71 @@ void HiresTexture::Prefetch()
notification += 10;
}
}
for (const auto& entry : s_enviromentMap)
{
const std::string& base_filename = entry.first;
std::unique_lock<std::mutex> lk(s_textureCacheMutex);
auto iter = s_enviromentCache.find(base_filename);
if (iter == s_enviromentCache.end())
{
lk.unlock();
HiresTexture* ptr = LoadEnviroment(
base_filename, [](size_t requested_size) { return new u8[requested_size]; }, true);
lk.lock();
if (ptr != nullptr)
{
size_sum.fetch_add(ptr->m_cached_data_size);
iter = s_enviromentCache.insert(
iter, std::make_pair(base_filename, std::shared_ptr<HiresTexture>(ptr)));
}
}
if (s_textureCacheAbortLoading.IsSet())
{
if (g_ActiveConfig.bWaitForCacheHiresTextures)
{
Host_UpdateProgressDialog("", -1, -1);
}
return;
}
if (size_sum.load() > max_mem)
{
Config::SetCurrent(Config::GFX_HIRES_TEXTURES, false);
OSD::AddMessage(
StringFromFormat(
"Custom Textures prefetching after %.1f MB aborted, not enough RAM available",
size_sum / (1024.0 * 1024.0)),
10000);
if (g_ActiveConfig.bWaitForCacheHiresTextures)
{
Host_UpdateProgressDialog("", -1, -1);
}
return;
}
count++;
size_t percent = (count * 100) / total;
if (percent >= notification)
{
if (g_ActiveConfig.bWaitForCacheHiresTextures)
{
Host_UpdateProgressDialog(GetStringT("Prefetching Custom Textures...").c_str(),
static_cast<int>(count), static_cast<int>(total));
}
else
{
OSD::AddMessage(StringFromFormat("Custom Textures prefetching %.1f MB %zu %% finished",
size_sum / (1024.0 * 1024.0), percent),
2000);
}
notification += 10;
}
}
if (g_ActiveConfig.bWaitForCacheHiresTextures)
{
Host_UpdateProgressDialog("", -1, -1);
@ -535,8 +720,8 @@ HiresTexture::Search(const std::string& basename,
lk.unlock();
if (size_sum.load() < max_mem)
{
std::shared_ptr<HiresTexture> ptr(
Load(basename, [](size_t requested_size) { return new u8[requested_size]; }, true));
std::shared_ptr<HiresTexture> ptr(Load(
basename, [](size_t requested_size) { return new u8[requested_size]; }, true));
lk.lock();
if (ptr)
{
@ -552,6 +737,56 @@ HiresTexture::Search(const std::string& basename,
return std::shared_ptr<HiresTexture>(Load(basename, request_buffer_delegate, false));
}
bool HiresTexture::EnviromentExists(const std::string& basename)
{
if (s_enviromentMap.size() == 0 || !g_ActiveConfig.HiresMaterialMapsEnabled())
{
return false;
}
EnvTextureCache::iterator iter = s_enviromentMap.find(basename);
if (iter == s_enviromentMap.end())
{
return false;
}
return true;
}
std::shared_ptr<HiresTexture>
HiresTexture::SearchEnviroment(const std::string& basename,
std::function<u8*(size_t)> request_buffer_delegate)
{
if (g_ActiveConfig.bCacheHiresTextures)
{
std::unique_lock<std::mutex> lk(s_textureCacheMutex);
auto iter = s_enviromentCache.find(basename);
if (iter != s_enviromentCache.end())
{
HiresTexture* current = iter->second.get();
u8* dst = request_buffer_delegate(current->m_cached_data_size);
memcpy(dst, current->m_cached_data.get(), current->m_cached_data_size);
return iter->second;
}
lk.unlock();
if (size_sum.load() < max_mem)
{
std::shared_ptr<HiresTexture> ptr(LoadEnviroment(
basename, [](size_t requested_size) { return new u8[requested_size]; }, true));
lk.lock();
if (ptr)
{
s_enviromentCache[basename] = ptr;
HiresTexture* current = ptr.get();
size_sum.fetch_add(current->m_cached_data_size);
u8* dst = request_buffer_delegate(current->m_cached_data_size);
memcpy(dst, current->m_cached_data.get(), current->m_cached_data_size);
}
return ptr;
}
}
return std::shared_ptr<HiresTexture>(LoadEnviroment(basename, request_buffer_delegate, false));
}
ImageLoaderParams LoadMipLevel(const hires_mip_level& item,
const std::function<u8*(size_t, bool)>& bufferdelegate,
bool cacheresult)
@ -864,3 +1099,131 @@ HiresTexture* HiresTexture::Load(const std::string& basename,
}
return ret;
}
HiresTexture* HiresTexture::LoadEnviroment(const std::string& basename,
std::function<u8*(size_t)> request_buffer_delegate,
bool cacheresult)
{
if (s_enviromentMap.size() == 0 || !g_ActiveConfig.HiresMaterialMapsEnabled())
{
return nullptr;
}
EnvTextureCache::iterator iter = s_enviromentMap.find(basename);
if (iter == s_enviromentMap.end())
{
return nullptr;
}
// all enviroment faces are mandatory
EnvTextureCacheItem& current = iter->second;
bool complete = current.maps.size() == (EnvType::negativeZ + 1);
size_t levels = SIZE_MAX;
for (size_t i = 0; i < current.maps.size(); i++)
{
levels = std::min(levels, current.maps[i].size());
if (current.maps[i].size() == 0)
{
complete = false;
break;
}
}
if (!complete)
{
return nullptr;
}
HiresTexture* ret = nullptr;
u8* buffer_pointer;
u32 maxwidth = 0;
u32 maxheight = 0;
bool last_level_is_dds = false;
bool allocated_data = false;
bool mipmapsize_included = false;
size_t remaining_buffer_size = 0;
size_t total_buffer_size = 0;
std::function<u8*(size_t, bool)> first_level_function = [&](size_t requiredsize,
bool mipmapsincluded) {
// Allocate double side buffer if we are going to load normal maps
allocated_data = true;
mipmapsize_included = mipmapsincluded;
// Pre allocate space for the textures and potetially all the posible mip levels
if (levels > 1 && !mipmapsincluded)
{
requiredsize = (requiredsize * 4) / 3;
}
total_buffer_size = requiredsize * (EnvType::negativeZ + 1);
remaining_buffer_size = total_buffer_size;
buffer_pointer = request_buffer_delegate(total_buffer_size);
return buffer_pointer;
};
std::function<u8*(size_t, bool)> allocation_function = [&](size_t requiredsize,
bool mipmapsincluded) {
// is required size is biguer that the remaining size on the packed buffer just reject
if (requiredsize > remaining_buffer_size)
{
return static_cast<u8*>(nullptr);
}
// just return the pointer to pack the textures in a single buffer.
return buffer_pointer;
};
for (size_t i = 0; i < current.maps.size(); i++)
{
for (size_t level = 0; level < levels; level++)
{
const hires_mip_level& item = current.maps[i][level];
ImageLoaderParams imgInfo =
LoadMipLevel(item, i == 0 && level == 0 ? first_level_function : allocation_function, cacheresult);
imgInfo.releaseresourcesonerror = cacheresult;
bool ddsfile = item.is_compressed && TexDecoder::IsCompressed(imgInfo.resultTex);
if ((level > 0 && ddsfile != last_level_is_dds) || imgInfo.dst == nullptr ||
imgInfo.resultTex == PC_TEX_FMT_NONE)
{
// don't give support to mixed formats
if (allocated_data && cacheresult && imgInfo.dst != nullptr)
{
delete[] imgInfo.dst;
}
break;
}
last_level_is_dds = ddsfile;
if (level == 0 && i == 0)
{
ret = new HiresTexture();
ret->has_arbitrary_mips = current.has_arbitrary_mips;
ret->m_format = imgInfo.resultTex;
ret->m_width = maxwidth = imgInfo.Width;
ret->m_height = maxheight = imgInfo.Height;
if (cacheresult)
{
ret->m_cached_data.reset(imgInfo.dst);
ret->m_cached_data_size = total_buffer_size;
}
}
else
{
if (!ValidateImage(imgInfo, level, maxwidth, maxheight, ret->m_format, "color"))
break;
}
buffer_pointer = imgInfo.dst + imgInfo.data_size;
remaining_buffer_size -= imgInfo.data_size;
if (imgInfo.nummipmaps > 0)
{
// Give priority to load dds with packed levels
ret->m_levels = imgInfo.nummipmaps + 1;
break;
}
else if (i == 0)
{
ret->m_levels++;
}
// no more mipmaps available
if (maxwidth == 1 && maxheight == 1)
break;
maxwidth = std::max(maxwidth >> 1, 1u);
maxheight = std::max(maxheight >> 1, 1u);
}
}
return ret;
}

View file

@ -19,27 +19,35 @@ public:
static void Shutdown();
static std::shared_ptr<HiresTexture> Search(const std::string& basename,
std::function<u8*(size_t)> request_buffer_delegate
);
std::function<u8*(size_t)> request_buffer_delegate);
static std::string GenBaseName(
const u8* texture, size_t texture_size,
const u8* tlut, size_t tlut_size,
u32 width, u32 height,
int format,
bool has_mipmaps,
bool dump = false);
static std::shared_ptr<HiresTexture>
SearchEnviroment(const std::string& basename, std::function<u8*(size_t)> request_buffer_delegate);
~HiresTexture()
{};
static bool EnviromentExists(const std::string& basename);
static std::string GenBaseName(const u8* texture, size_t texture_size, const u8* tlut,
size_t tlut_size, u32 width, u32 height, int format,
bool has_mipmaps, bool dump = false);
~HiresTexture(){};
HostTextureFormat m_format;
u32 m_width, m_height, m_levels, m_nrm_levels, m_lum_levels;
bool has_arbitrary_mips;
std::unique_ptr<u8> m_cached_data;
size_t m_cached_data_size;
private:
static void ProccessTexture(const std::string& fileitem, std::string& filename,
const std::string& extension,
const bool BuildMaterialMaps);
static void ProccessEnviroment(const std::string& fileitem, std::string& filename,
const std::string& extension);
static HiresTexture* Load(const std::string& base_filename,
std::function<u8*(size_t)> request_buffer_delegate, bool cacheresult);
std::function<u8*(size_t)> request_buffer_delegate, bool cacheresult);
static HiresTexture* LoadEnviroment(const std::string& base_filename,
std::function<u8*(size_t)> request_buffer_delegate,
bool cacheresult);
static void Prefetch();
HiresTexture();

File diff suppressed because it is too large Load diff

View file

@ -204,6 +204,25 @@ void TextureCacheBase::Cleanup(s32 _frameCount)
++iter;
}
}
auto env_iter = enviroment_cache.begin();
auto env_end = enviroment_cache.end();
while (env_iter != env_end)
{
if (env_iter->second.frameCount == FRAMECOUNT_INVALID)
{
env_iter->second.frameCount = _frameCount;
}
if (_frameCount > texture_kill_threshold + env_iter->second.frameCount)
{
env_iter = enviroment_cache.erase(env_iter);
}
else
{
env_iter->second.last_frame_hits = env_iter->second.hits;
env_iter->second.hits = 0;
++env_iter;
}
}
TexPool::iterator iter2 = texture_pool.begin();
TexPool::iterator tcend2 = texture_pool.end();
while (iter2 != tcend2)
@ -485,6 +504,103 @@ void TextureCacheBase::BindTextures()
bound_textures[i]->texture->Bind(i);
}
}
if (g_ActiveConfig.HiresMaterialMapsEnabled() && g_ActiveConfig.bForcePhongShading)
{
SetupEnviromentTexture();
if (bound_enviroment)
{
bound_enviroment->texture->Bind(8);
}
}
}
void TextureCacheBase::SetupEnviromentTexture()
{
if (enviroment_cache.size() == 0 && HiresTexture::EnviromentExists("default"))
{
LoadEnviromentTexture("default");
}
for (u32 i = 0; i < bound_textures.size(); ++i)
{
if (IsValidBindPoint(static_cast<u32>(i)) && bound_textures[i])
{
auto env_iter = enviroment_cache.find(bound_textures[i]->basename);
if (env_iter == enviroment_cache.end() &&
HiresTexture::EnviromentExists(bound_textures[i]->basename))
{
LoadEnviromentTexture(bound_textures[i]->basename);
}
else
{
env_iter->second.frameCount = FRAMECOUNT_INVALID;
env_iter->second.hits++;
}
}
}
auto env_iter = enviroment_cache.begin();
auto env_end = enviroment_cache.end();
u64 currenthits = 0;
TCacheEntry* current = nullptr;
if (env_iter != env_end)
{
env_iter->second.frameCount = FRAMECOUNT_INVALID;
current = env_iter->second.envtexture;
env_iter++;
}
while (env_iter != env_end)
{
if (env_iter->second.last_frame_hits > currenthits)
{
currenthits = env_iter->second.last_frame_hits;
current = env_iter->second.envtexture;
}
}
bound_enviroment = current;
}
void TextureCacheBase::LoadEnviromentTexture(std::string basename)
{
auto env_tex = HiresTexture::SearchEnviroment(basename, [this](size_t required_size) {
this->CheckTempSize(required_size);
return this->temp;
});
if (env_tex)
{
TextureConfig config;
config.width = env_tex->m_width;
config.height = env_tex->m_height;
config.levels = env_tex->m_levels;
config.pcformat = env_tex->m_format;
config.enviroment = true;
config.layers = 6;
TCacheEntry* entry = AllocateCacheEntry(config);
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
enviroment_cache.emplace(basename, entry);
entry->SetGeneralParameters(0, 0, 0);
entry->SetDimensions(env_tex->m_width, env_tex->m_height, env_tex->m_levels);
entry->SetHiresParams(true, basename, false, false, env_tex->has_arbitrary_mips, true);
entry->SetHashes(0, 0);
entry->is_efb_copy = false;
int currentlayer = 0;
u8* Bufferptr = TextureCacheBase::temp;
for (size_t i = 0; i < 6; i++)
{
entry->texture->Load(Bufferptr, config.width, config.height, config.width, 0,
currentlayer);
Bufferptr += TextureUtil::GetTextureSizeInBytes(config.width, config.height, config.pcformat);
for (u32 level = 1; level != env_tex->m_levels; ++level)
{
u32 mip_width = TextureUtil::CalculateLevelSize(config.width, level);
u32 mip_height = TextureUtil::CalculateLevelSize(config.height, level);
entry->texture->Load(Bufferptr, mip_width, mip_height, mip_width, level, currentlayer);
Bufferptr += TextureUtil::GetTextureSizeInBytes(mip_width, mip_height, config.pcformat);
}
currentlayer++;
}
}
}
TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage)
@ -841,7 +957,7 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage)
entry->SetGeneralParameters(address, texture_size, full_format);
entry->SetDimensions(nativeW, nativeH, tex_levels);
entry->SetHiresParams(!!hires_tex, basename, use_scaling, emissivematerial,
!!hires_tex && hires_tex->has_arbitrary_mips);
!!hires_tex && hires_tex->has_arbitrary_mips, false);
entry->SetHashes(full_hash, tex_hash);
entry->is_efb_copy = false;
@ -1000,23 +1116,24 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, u32 dstFormat, u32
// - EFB to RAM:
// Encodes the requested EFB data at its native resolution to the emulated RAM using shaders.
// Load() decodes the data from there again (using TextureDecoder) if the EFB copy is being
//used as a texture again. Advantage: CPU can read data from the EFB copy and we don't lose any
//important updates to the texture Disadvantage: Encoding+decoding steps often are redundant
//because only some games read or modify EFB copies before using them as textures.
// used as a texture again. Advantage: CPU can read data from the EFB copy and we don't lose
// any important updates to the texture Disadvantage: Encoding+decoding steps often are
// redundant because only some games read or modify EFB copies before using them as textures.
//
// - EFB to texture:
// Copies the requested EFB data to a texture object in VRAM, performing any color conversion
//using shaders. Advantage: Works for many games, since in most cases EFB copies aren't read or
//modified at all before being used as a texture again. Since we don't do any further encoding or
//decoding here, this method is much faster. It also allows enhancing the visual quality by doing
//scaled EFB copies.
// using shaders. Advantage: Works for many games, since in most cases EFB copies aren't read
// or modified at all before being used as a texture again. Since we don't do any
// further
// encoding or decoding here, this method is much faster. It also allows enhancing the
// visual quality by doing scaled EFB copies.
//
// - Hybrid EFB copies:
// 1a) Whenever this function gets called, encode the requested EFB data to RAM (like EFB to
//RAM) 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination address
//range. If EFB copy caching is enabled, further checks will (try to) prevent redundant EFB
//copies. 2) Check if a texture cache entry for the specified dstAddr already exists (i.e. if an
//EFB copy was triggered to that address before): 2a) Entry doesn't exist:
// RAM) 1b) Set type to TCET_EC_DYNAMIC for all texture cache entries in the destination
// address range. If EFB copy caching is enabled, further checks will (try to) prevent
// redundant EFB copies. 2) Check if a texture cache entry for the specified dstAddr already
// exists (i.e. if an EFB copy was triggered to that address before): 2a) Entry doesn't exist:
// - Also copy the requested EFB data to a texture object in VRAM (like EFB to texture)
// - Create a texture cache entry for the target (type = TCET_EC_VRAM)
// - Store a hash of the encoded RAM data in the texcache entry.
@ -1024,20 +1141,22 @@ void TextureCacheBase::CopyRenderTargetToTexture(u32 dstAddr, u32 dstFormat, u32
// - Like case 2a, but reuse the old texcache entry instead of creating a new one.
// 2c) Entry exists AND type is TCET_EC_DYNAMIC:
// - Only encode the texture to RAM (like EFB to RAM) and store a hash of the encoded data in
//the existing texcache entry.
// the existing texcache entry.
// - Do NOT copy the requested EFB data to a VRAM object. Reason: the texture is dynamic,
//i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up
//deleting it and reloading the data from RAM anyway. 3) If the EFB copy gets used as a texture,
//compare the source RAM hash with the hash you stored when encoding the EFB data to RAM. 3a) If
//the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created 3b) If the two
//hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type to
//TCET_EC_DYNAMIC. Redecode the source RAM data to a VRAM object. The entry basically behaves like
//a normal texture now. 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal texture.
// Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to texture.
// i.e. the CPU is modifying it. Storing a VRAM copy is useless, because we'd always end up
// deleting it and reloading the data from RAM anyway. 3) If the EFB copy gets used as a
// texture, compare the source RAM hash with the hash you stored when encoding the EFB data to
// RAM. 3a) If the two hashes match AND type is TCET_EC_VRAM, reuse the VRAM copy you created
// 3b) If the two hashes differ AND type is TCET_EC_VRAM, screw your existing VRAM copy. Set type
// to TCET_EC_DYNAMIC. Redecode the source RAM data to a VRAM object. The entry basically
// behaves
// like a normal texture now. 3c) If type is TCET_EC_DYNAMIC, treat the EFB copy like a normal
// texture. Advantage: Non-dynamic EFB copies can be visually enhanced like with EFB to
// texture.
// Compatibility is as good as EFB to RAM.
// Disadvantage: Slower than EFB to texture and often even slower than EFB to RAM.
// EFB copy cache depends on accurate texture hashing being enabled. However, with
//accurate hashing you end up being as slow as without a copy cache anyway.
// accurate hashing you end up being as slow as without a copy cache anyway.
//
// Disadvantage of all methods: Calling this function requires the GPU to perform a pipeline flush
// which stalls any further CPU processing.

View file

@ -8,18 +8,18 @@
#include <bitset>
#include <map>
#include <memory>
#include <vector>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Thread.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/HostTexture.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/TextureConfig.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VideoCommon.h"
struct VideoConfig;
@ -38,16 +38,17 @@ enum TextureCacheParams
class TextureCacheBase
{
public:
public:
struct TCacheEntry
{
std::unique_ptr<HostTexture> texture;
// common members
// common members
u32 addr = {};
u32 size_in_bytes = {};
u32 format = {}; // bits 0-3 will contain the in-memory format.
u32 format = {}; // bits 0-3 will contain the in-memory format.
u32 memory_stride = {};
u32 native_width = {}, native_height = {}; // Texture dimensions from the GameCube's point of view
u32 native_width = {},
native_height = {}; // Texture dimensions from the GameCube's point of view
u32 native_levels = {};
// used to delete textures which haven't been used for TEXTURE_KILL_THRESHOLD frames
s32 frameCount = FRAMECOUNT_INVALID;
@ -55,6 +56,7 @@ public:
u64 base_hash = {};
bool is_efb_copy = false;
bool is_custom_tex = false;
bool is_enviroment_tex = false;
bool has_arbitrary_mips = false;
bool material_map = false;
bool is_scaled = false;
@ -73,7 +75,8 @@ public:
std::string basename;
explicit TCacheEntry(std::unique_ptr<HostTexture> tex, bool material = false, bool luma = false);
explicit TCacheEntry(std::unique_ptr<HostTexture> tex, bool material = false,
bool luma = false);
~TCacheEntry();
@ -92,13 +95,15 @@ public:
memory_stride = _native_width;
}
void SetHiresParams(bool _is_custom_tex, const std::string & _basename, bool _is_scaled, bool _emissive, bool arbitrary_mips)
void SetHiresParams(bool _is_custom_tex, const std::string& _basename, bool _is_scaled,
bool _emissive, bool arbitrary_mips, bool is_enviroment)
{
is_custom_tex = _is_custom_tex;
basename = _basename;
is_scaled = _is_scaled;
emissive = _emissive;
has_arbitrary_mips = arbitrary_mips;
is_enviroment_tex = is_enviroment;
}
void SetHashes(u64 _hash, u64 _base_hash)
@ -127,10 +132,7 @@ public:
bool OverlapsMemoryRange(u32 range_address, u32 range_size) const;
bool IsEfbCopy() const
{
return is_efb_copy;
}
bool IsEfbCopy() const { return is_efb_copy; }
u32 NumBlocksY() const;
u32 BytesPerRow() const;
@ -139,7 +141,7 @@ public:
const TextureConfig GetConfig() const { return texture->GetConfig(); }
};
virtual ~TextureCacheBase(); // needs virtual for DX11 dtor
virtual ~TextureCacheBase(); // needs virtual for DX11 dtor
void OnConfigChanged(VideoConfig& config);
// Removes textures which aren't used for more than TEXTURE_KILL_THRESHOLD frames,
@ -147,16 +149,16 @@ public:
void Cleanup(s32 _frameCount);
void Invalidate();
virtual HostTextureFormat GetHostTextureFormat(const s32 texformat,
const TlutFormat tlutfmt, u32 width, u32 height) = 0;
virtual HostTextureFormat GetHostTextureFormat(const s32 texformat, const TlutFormat tlutfmt,
u32 width, u32 height) = 0;
virtual bool Palettize(TCacheEntry* entry, const TCacheEntry* base_entry) = 0;
virtual void CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, u32 bytes_per_row,
u32 num_blocks_y, u32 memory_stride,
bool is_depth_copy, const EFBRectangle& src_rect, bool scale_by_half) = 0;
u32 num_blocks_y, u32 memory_stride, bool is_depth_copy,
const EFBRectangle& src_rect, bool scale_by_half) = 0;
virtual bool CompileShaders() = 0; // currently only implemented by OGL
virtual void DeleteShaders() = 0; // currently only implemented by OGL
virtual bool CompileShaders() = 0; // currently only implemented by OGL
virtual void DeleteShaders() = 0; // currently only implemented by OGL
virtual void LoadLut(u32 lutFmt, void* addr, u32 size) = 0;
@ -164,12 +166,11 @@ public:
void InvalidateAllBindPoints() { valid_bind_points.reset(); }
bool IsValidBindPoint(u32 i) const { return valid_bind_points.test(i); }
virtual void BindTextures();
void CopyRenderTargetToTexture(u32 dstAddr, u32 dstFormat, u32 dstStride,
bool is_depth_copy, const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
u8* GetTemporalBuffer()
{
return temp;
}
void SetupEnviromentTexture();
void LoadEnviromentTexture(std::string basename);
void CopyRenderTargetToTexture(u32 dstAddr, u32 dstFormat, u32 dstStride, bool is_depth_copy,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
u8* GetTemporalBuffer() { return temp; }
// Returns true if the texture data and palette formats are supported by the GPU decoder.
virtual bool SupportsGPUTextureDecode(TextureFormat format, TlutFormat palette_format)
{
@ -179,48 +180,63 @@ public:
// width, height are the size of the image in pixels.
// aligned_width, aligned_height are the size of the image in pixels, aligned to the block size.
// row_stride is the number of bytes for a row of blocks, not pixels.
virtual bool DecodeTextureOnGPU(HostTexture* dst, u32 dst_level, const u8* data,
u32 data_size, TextureFormat tformat, u32 width, u32 height,
u32 aligned_width, u32 aligned_height, u32 row_stride,
const u8* palette, TlutFormat palette_format)
virtual bool DecodeTextureOnGPU(HostTexture* dst, u32 dst_level, const u8* data, u32 data_size,
TextureFormat tformat, u32 width, u32 height, u32 aligned_width,
u32 aligned_height, u32 row_stride, const u8* palette,
TlutFormat palette_format)
{
return false;
}
std::unique_ptr<HostTexture> AllocateTexture(const TextureConfig& config);
void DisposeTexture(std::unique_ptr<HostTexture>& texture);
protected:
alignas(16) u8 *temp = {};
alignas(16) u8* temp = {};
size_t temp_size = {};
std::array<TCacheEntry*, 8> bound_textures{};
TCacheEntry* bound_enviroment{};
std::bitset<8> valid_bind_points;
TextureCacheBase();
private:
virtual std::unique_ptr<HostTexture> CreateTexture(const TextureConfig& config) = 0;
virtual std::unique_ptr<HostTexture> CreateTexture(const TextureConfig& config) = 0;
virtual void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
const EFBRectangle& src_rect, bool scale_by_half,
unsigned int cbuf_id, const float* colmat, u32 width, u32 height) = 0;
const EFBRectangle& src_rect, bool scale_by_half,
unsigned int cbuf_id, const float* colmat, u32 width,
u32 height) = 0;
// Minimal version of TCacheEntry just for TexPool
struct TexPoolEntry
{
std::unique_ptr<HostTexture> texture;
s32 frameCount = FRAMECOUNT_INVALID;
s64 frameCount = FRAMECOUNT_INVALID;
TexPoolEntry(std::unique_ptr<HostTexture> tex) : texture(std::move(tex)) {}
};
struct EnvCacheEntry
{
TCacheEntry* envtexture;
u64 last_frame_hits = 0;
u64 hits = 0;
s64 frameCount = FRAMECOUNT_INVALID;
EnvCacheEntry(TCacheEntry* tex) : envtexture(tex) {}
};
using TexAddrCache = std::multimap<u32, TCacheEntry*>;
using TexHashCache = std::multimap<u64, TCacheEntry*>;
using EnviromentCache = std::unordered_map<std::string, EnvCacheEntry>;
using TexPool = std::unordered_multimap<TextureConfig, TexPoolEntry, TextureConfig::Hasher>;
void SetBackupConfig(const VideoConfig& config);
void ScaleTextureCacheEntryTo(TCacheEntry* entry, u32 new_width, u32 new_height);
void CheckTempSize(size_t required_size);
TCacheEntry* DoPartialTextureUpdates(TCacheEntry* entry_to_update, u32 tlutaddr, u32 tlutfmt, u32 palette_size);
TCacheEntry* DoPartialTextureUpdates(TCacheEntry* entry_to_update, u32 tlutaddr, u32 tlutfmt,
u32 palette_size);
TCacheEntry* ApplyPaletteToEntry(TCacheEntry* entry, u32 tlutaddr, u32 tlutfmt, u32 palette_size);
void DumpTexture(TCacheEntry* entry, std::string basename, u32 level);
TCacheEntry* AllocateCacheEntry(const TextureConfig& config, bool materialmap = false, bool luma = false);
TCacheEntry* AllocateCacheEntry(const TextureConfig& config, bool materialmap = false,
bool luma = false);
void DisposeCacheEntry(TCacheEntry* texture);
TexPool::iterator FindMatchingTextureFromPool(const TextureConfig& config);
@ -231,10 +247,11 @@ private:
// Return all possible overlapping textures. As addr+size of the textures is not
// indexed, this may return false positives.
std::pair<TexAddrCache::iterator, TexAddrCache::iterator>
FindOverlappingTextures(u32 addr, u32 size_in_bytes);
FindOverlappingTextures(u32 addr, u32 size_in_bytes);
TexAddrCache textures_by_address;
TexHashCache textures_by_hash;
EnviromentCache enviroment_cache;
TexPool texture_pool;
size_t texture_pool_memory_usage = {};

View file

@ -32,8 +32,8 @@ struct TextureConfig
bool operator == (const TextureConfig& o) const
{
return std::tie(width, height, levels, layers, rendertarget, pcformat) ==
std::tie(o.width, o.height, o.levels, o.layers, o.rendertarget, o.pcformat);
return std::tie(width, height, levels, layers, rendertarget, enviroment, pcformat) ==
std::tie(o.width, o.height, o.levels, o.layers, o.rendertarget, o.enviroment, o.pcformat);
}
MathUtil::Rectangle<int> GetRect() const
@ -45,7 +45,8 @@ struct TextureConfig
{
size_t operator()(const TextureConfig& c) const
{
return (u64)c.rendertarget << 56 // 1 bit
return (u64)c.enviroment << 57 // 1 bit
| (u64)c.rendertarget << 56 // 1 bit
| (u64)c.pcformat << 48 // 8 bits
| (u64)c.layers << 40 // 8 bits
| (u64)c.levels << 32 // 8 bits
@ -56,5 +57,6 @@ struct TextureConfig
u32 width = 0, height = 0, levels = 1, layers = 1;
bool rendertarget = false;
bool enviroment = false;
HostTextureFormat pcformat = PC_TEX_FMT_NONE;
};

View file

@ -155,7 +155,8 @@ static void SetSamplerState(u32 index, bool custom_tex, bool has_arbitrary_mips,
{
state.min_filter = SamplerState::Filter::Linear;
state.mag_filter = SamplerState::Filter::Linear;
state.mipmap_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ?
state.mipmap_filter =
mip_maps_enabled ?
SamplerState::Filter::Linear :
SamplerState::Filter::Point;
}
@ -184,7 +185,7 @@ static void SetSamplerState(u32 index, bool custom_tex, bool has_arbitrary_mips,
{
state.min_filter = SamplerState::Filter::Linear;
state.mag_filter = SamplerState::Filter::Linear;
if (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0))
if (mip_maps_enabled)
state.mipmap_filter = SamplerState::Filter::Linear;
}
state.anisotropic_filtering = 1;
@ -289,6 +290,15 @@ void VertexManagerBase::DoFlush()
ERROR_LOG(VIDEO, "error loading texture");
}
}
if (g_ActiveConfig.bForcePhongShading)
{
SamplerState state = {};
state.min_filter = SamplerState::Filter::Linear;
state.mag_filter = SamplerState::Filter::Linear;
state.mipmap_filter = SamplerState::Filter::Linear;
state.max_lod = 255;
g_renderer->SetSamplerState(8, state);
}
if (g_ActiveConfig.HiresMaterialMapsEnabled())
{
PixelShaderManager::SetFlags(0, ~0, material_mask);