mirror of
https://github.com/Tinob/Ishiiruka.git
synced 2024-06-16 03:17:27 -04:00
Implement experimental support for static environment cube maps to improve support basic reflection in plastic and metallic materials
This commit is contained in:
parent
ad82a074f8
commit
bf7957cfbf
BIN
Data/Sys/Resources/env_default.nx.dds
Normal file
BIN
Data/Sys/Resources/env_default.nx.dds
Normal file
Binary file not shown.
BIN
Data/Sys/Resources/env_default.ny.dds
Normal file
BIN
Data/Sys/Resources/env_default.ny.dds
Normal file
Binary file not shown.
BIN
Data/Sys/Resources/env_default.nz.dds
Normal file
BIN
Data/Sys/Resources/env_default.nz.dds
Normal file
Binary file not shown.
BIN
Data/Sys/Resources/env_default.px.dds
Normal file
BIN
Data/Sys/Resources/env_default.px.dds
Normal file
Binary file not shown.
BIN
Data/Sys/Resources/env_default.py.dds
Normal file
BIN
Data/Sys/Resources/env_default.py.dds
Normal file
Binary file not shown.
BIN
Data/Sys/Resources/env_default.pz.dds
Normal file
BIN
Data/Sys/Resources/env_default.pz.dds
Normal file
Binary file not shown.
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -285,7 +285,7 @@ void XFBSource::CopyEFB(float gamma)
|
|||
texdesc.Format,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
texdesc.Format,
|
||||
false,
|
||||
false, false,
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -73,6 +73,8 @@ enum BaseType
|
|||
Unorm8
|
||||
};
|
||||
|
||||
class D3DTexture2D;
|
||||
|
||||
class TextureEncoder
|
||||
{
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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 = {};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue