#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" #include "D3D12GSRender.h" #include "d3dx12.h" #include "../Common/TextureUtils.h" // For clarity this code deals with texture but belongs to D3D12GSRender class #include "D3D12Formats.h" #include "../rsx_methods.h" bool is_dxtc_format(u32 texture_format) { switch (texture_format) { case CELL_GCM_TEXTURE_COMPRESSED_DXT1: case CELL_GCM_TEXTURE_COMPRESSED_DXT23: case CELL_GCM_TEXTURE_COMPRESSED_DXT45: return true; default: return false; } } namespace { D3D12_COMPARISON_FUNC get_sampler_compare_func[] = { D3D12_COMPARISON_FUNC_NEVER, D3D12_COMPARISON_FUNC_LESS, D3D12_COMPARISON_FUNC_EQUAL, D3D12_COMPARISON_FUNC_LESS_EQUAL, D3D12_COMPARISON_FUNC_GREATER, D3D12_COMPARISON_FUNC_NOT_EQUAL, D3D12_COMPARISON_FUNC_GREATER_EQUAL, D3D12_COMPARISON_FUNC_ALWAYS }; D3D12_SAMPLER_DESC get_sampler_desc(const rsx::fragment_texture &texture) { D3D12_SAMPLER_DESC samplerDesc = {}; samplerDesc.Filter = get_texture_filter(texture.min_filter(), texture.mag_filter()); samplerDesc.AddressU = get_texture_wrap_mode(texture.wrap_s()); samplerDesc.AddressV = get_texture_wrap_mode(texture.wrap_t()); samplerDesc.AddressW = get_texture_wrap_mode(texture.wrap_r()); samplerDesc.ComparisonFunc = get_sampler_compare_func[texture.zfunc()]; samplerDesc.MaxAnisotropy = get_texture_max_aniso(texture.max_aniso()); samplerDesc.MipLODBias = texture.bias(); samplerDesc.BorderColor[0] = (FLOAT)texture.border_color(); samplerDesc.BorderColor[1] = (FLOAT)texture.border_color(); samplerDesc.BorderColor[2] = (FLOAT)texture.border_color(); samplerDesc.BorderColor[3] = (FLOAT)texture.border_color(); samplerDesc.MinLOD = (FLOAT)(texture.min_lod() >> 8); samplerDesc.MaxLOD = (FLOAT)(texture.max_lod() >> 8); return samplerDesc; } namespace { CD3DX12_RESOURCE_DESC get_texture_description(const rsx::fragment_texture &texture) { const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); DXGI_FORMAT dxgi_format = get_texture_format(format); u16 width = texture.width(); u16 height = texture.height(); u16 depth = texture.depth(); u16 miplevels = texture.get_exact_mipmap_count(); // DXTC uses 4x4 block texture and align to multiple of 4. if (is_dxtc_format(format)) { width = align(width, 4); height = align(height, 4); } switch (texture.get_extended_texture_dimension()) { case rsx::texture_dimension_extended::texture_dimension_1d: return CD3DX12_RESOURCE_DESC::Tex1D(dxgi_format, width, 1, miplevels); case rsx::texture_dimension_extended::texture_dimension_2d: return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, width, height, 1, miplevels); case rsx::texture_dimension_extended::texture_dimension_cubemap: return CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, width, height, 6, miplevels); case rsx::texture_dimension_extended::texture_dimension_3d: return CD3DX12_RESOURCE_DESC::Tex3D(dxgi_format, width, height, depth, miplevels); } fmt::throw_exception("Unknown texture dimension" HERE); } } namespace { /** * Allocate buffer in texture_buffer_heap big enough and upload data into existing_texture which should be in COPY_DEST state */ void update_existing_texture( const rsx::fragment_texture &texture, ID3D12GraphicsCommandList *command_list, d3d12_data_heap &texture_buffer_heap, ID3D12Resource *existing_texture) { size_t w = texture.width(), h = texture.height(); const u8 format = texture.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); DXGI_FORMAT dxgi_format = get_texture_format(format); size_t buffer_size = get_placed_texture_storage_size(texture, 256); size_t heap_offset = texture_buffer_heap.alloc(buffer_size); size_t mip_level = 0; void *mapped_buffer_ptr = texture_buffer_heap.map(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); gsl::span mapped_buffer{ (gsl::byte*)mapped_buffer_ptr, ::narrow(buffer_size) }; std::vector input_layouts = get_subresources_layout(texture); u8 block_size_in_bytes = get_format_block_size_in_bytes(format); u8 block_size_in_texel = get_format_block_size_in_texel(format); bool is_swizzled = !(texture.format() & CELL_GCM_TEXTURE_LN); size_t offset_in_buffer = 0; for (const rsx_subresource_layout &layout : input_layouts) { upload_texture_subresource(mapped_buffer.subspan(offset_in_buffer), layout, format, is_swizzled, 256); UINT row_pitch = align(layout.width_in_block * block_size_in_bytes, 256); command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existing_texture, (UINT)mip_level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(texture_buffer_heap.get_heap(), { heap_offset + offset_in_buffer, { dxgi_format, (UINT)layout.width_in_block * block_size_in_texel, (UINT)layout.height_in_block * block_size_in_texel, (UINT)layout.depth, row_pitch } }), nullptr); offset_in_buffer += row_pitch * layout.height_in_block * layout.depth; offset_in_buffer = align(offset_in_buffer, 512); mip_level++; } texture_buffer_heap.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existing_texture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ)); } } /** * Create a texture residing in default heap and generate uploads commands in commandList, * using a temporary texture buffer. */ ComPtr upload_single_texture( const rsx::fragment_texture &texture, ID3D12Device *device, ID3D12GraphicsCommandList *command_list, d3d12_data_heap &texture_buffer_heap) { ComPtr result; CHECK_HRESULT(device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &get_texture_description(texture), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(result.GetAddressOf()) )); update_existing_texture(texture, command_list, texture_buffer_heap, result.Get()); return result; } D3D12_SHADER_RESOURCE_VIEW_DESC get_srv_descriptor_with_dimensions(const rsx::fragment_texture &tex) { D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = {}; switch (tex.get_extended_texture_dimension()) { case rsx::texture_dimension_extended::texture_dimension_1d: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; shared_resource_view_desc.Texture1D.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; case rsx::texture_dimension_extended::texture_dimension_2d: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shared_resource_view_desc.Texture2D.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; case rsx::texture_dimension_extended::texture_dimension_cubemap: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; shared_resource_view_desc.TextureCube.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; case rsx::texture_dimension_extended::texture_dimension_3d: shared_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; shared_resource_view_desc.Texture3D.MipLevels = tex.get_exact_mipmap_count(); return shared_resource_view_desc; } fmt::throw_exception("Wrong texture dimension" HERE); } } void D3D12GSRender::upload_textures(ID3D12GraphicsCommandList *command_list, size_t texture_count) { for (u32 i = 0; i < texture_count; ++i) { if (!m_textures_dirty[i]) continue; m_textures_dirty[i] = false; if (!rsx::method_registers.fragment_textures[i].enabled()) { // Now fill remaining texture slots with dummy texture/sampler D3D12_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = {}; shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shader_resource_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; shader_resource_view_desc.Texture2D.MipLevels = 1; shader_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0); m_device->CreateShaderResourceView(m_dummy_texture, &shader_resource_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(m_current_texture_descriptors->GetCPUDescriptorHandleForHeapStart()) .Offset((UINT)i, m_descriptor_stride_srv_cbv_uav) ); D3D12_SAMPLER_DESC sampler_desc = {}; sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; m_device->CreateSampler(&sampler_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(m_current_sampler_descriptors->GetCPUDescriptorHandleForHeapStart()) .Offset((UINT)i, m_descriptor_stride_samplers)); continue; } size_t w = rsx::method_registers.fragment_textures[i].width(), h = rsx::method_registers.fragment_textures[i].height(); if (!w || !h) { LOG_ERROR(RSX, "Texture upload requested but invalid texture dimensions passed"); continue; } const u32 texaddr = rsx::get_address(rsx::method_registers.fragment_textures[i].offset(), rsx::method_registers.fragment_textures[i].location()); const u8 format = rsx::method_registers.fragment_textures[i].format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); bool is_swizzled = !(rsx::method_registers.fragment_textures[i].format() & CELL_GCM_TEXTURE_LN); ID3D12Resource *vram_texture; std::pair > *cached_texture = m_texture_cache.find_data_if_available(texaddr); bool is_render_target = false, is_depth_stencil_texture = false; if (vram_texture = m_rtts.get_texture_from_render_target_if_applicable(texaddr)) { is_render_target = true; } else if (vram_texture = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) { is_depth_stencil_texture = true; } else if (cached_texture != nullptr && (cached_texture->first == texture_entry(format, w, h, rsx::method_registers.fragment_textures[i].depth(), rsx::method_registers.fragment_textures[i].get_exact_mipmap_count()))) { if (cached_texture->first.m_is_dirty) { command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(cached_texture->second.Get(), D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST)); update_existing_texture(rsx::method_registers.fragment_textures[i], command_list, m_buffer_data, cached_texture->second.Get()); m_texture_cache.protect_data(texaddr, texaddr, get_texture_size(rsx::method_registers.fragment_textures[i])); } vram_texture = cached_texture->second.Get(); } else { if (cached_texture != nullptr) get_current_resource_storage().dirty_textures.push_back(m_texture_cache.remove_from_cache(texaddr)); ComPtr tex = upload_single_texture(rsx::method_registers.fragment_textures[i], m_device.Get(), command_list, m_buffer_data); std::wstring name = L"texture_@" + std::to_wstring(texaddr); tex->SetName(name.c_str()); vram_texture = tex.Get(); m_texture_cache.store_and_protect_data(texaddr, texaddr, get_texture_size(rsx::method_registers.fragment_textures[i]), format, w, h, rsx::method_registers.fragment_textures[i].depth(), rsx::method_registers.fragment_textures[i].get_exact_mipmap_count(), tex); } D3D12_SHADER_RESOURCE_VIEW_DESC shared_resource_view_desc = get_srv_descriptor_with_dimensions(rsx::method_registers.fragment_textures[i]); shared_resource_view_desc.Format = get_texture_format(format); bool requires_remap = false; std::array channel_mapping = {}; switch (format) { default: LOG_ERROR(RSX, "Unimplemented mapping for texture format: 0x%x", format); break; case CELL_GCM_TEXTURE_COMPRESSED_HILO8: case CELL_GCM_TEXTURE_COMPRESSED_DXT1: case CELL_GCM_TEXTURE_COMPRESSED_DXT23: case CELL_GCM_TEXTURE_COMPRESSED_DXT45: case CELL_GCM_TEXTURE_DEPTH24_D8: case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: case CELL_GCM_TEXTURE_DEPTH16: case CELL_GCM_TEXTURE_DEPTH16_FLOAT: case CELL_GCM_TEXTURE_X32_FLOAT: case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: case CELL_GCM_TEXTURE_R5G5B5A1: case CELL_GCM_TEXTURE_D1R5G5B5: case CELL_GCM_TEXTURE_A1R5G5B5: case CELL_GCM_TEXTURE_A4R4G4B4: case CELL_GCM_TEXTURE_R5G6B5: case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: shared_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; break; case CELL_GCM_TEXTURE_B8: shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0); break; case CELL_GCM_TEXTURE_G8B8: { u8 remap_a = rsx::method_registers.fragment_textures[i].remap() & 0x3; u8 remap_r = (rsx::method_registers.fragment_textures[i].remap() >> 2) & 0x3; u8 remap_g = (rsx::method_registers.fragment_textures[i].remap() >> 4) & 0x3; u8 remap_b = (rsx::method_registers.fragment_textures[i].remap() >> 6) & 0x3; if (is_render_target) { // ARGB format // Data comes from RTT, stored as RGBA already const int RemapValue[4] = { D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2 }; channel_mapping = { RemapValue[remap_r], RemapValue[remap_g], RemapValue[remap_b], RemapValue[remap_a] }; requires_remap = true; } else { // ARGB format // Data comes from RSX mem, stored as ARGB already const int RemapValue[4] = { D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1 }; channel_mapping = { RemapValue[remap_r], RemapValue[remap_g], RemapValue[remap_b], RemapValue[remap_a] }; requires_remap = true; } break; } case CELL_GCM_TEXTURE_R6G5B5: // TODO: Remap it to another format here, so it's not glitched out shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0); break; case CELL_GCM_TEXTURE_X16: shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0); break; case CELL_GCM_TEXTURE_Y16_X16: case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0); break; case CELL_GCM_TEXTURE_Y16_X16_FLOAT: shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1); break; case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0); break; case CELL_GCM_TEXTURE_D8R8G8B8: shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1); break; case CELL_GCM_TEXTURE_A8R8G8B8: { u8 remap_a = rsx::method_registers.fragment_textures[i].remap() & 0x3; u8 remap_r = (rsx::method_registers.fragment_textures[i].remap() >> 2) & 0x3; u8 remap_g = (rsx::method_registers.fragment_textures[i].remap() >> 4) & 0x3; u8 remap_b = (rsx::method_registers.fragment_textures[i].remap() >> 6) & 0x3; if (is_render_target) { // ARGB format // Data comes from RTT, stored as RGBA already const int RemapValue[4] = { D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2 }; channel_mapping = { RemapValue[remap_r], RemapValue[remap_g], RemapValue[remap_b], RemapValue[remap_a] }; requires_remap = true; } else if (is_depth_stencil_texture) { shared_resource_view_desc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0); } else { // ARGB format // Data comes from RSX mem, stored as ARGB already const int RemapValue[4] = { D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3 }; channel_mapping = { RemapValue[remap_r], RemapValue[remap_g], RemapValue[remap_b], RemapValue[remap_a] }; requires_remap = true; } break; } } if (requires_remap) { auto decoded_remap = rsx::method_registers.fragment_textures[i].decoded_remap(); u8 remapped_inputs[] = { decoded_remap.second[1], decoded_remap.second[2], decoded_remap.second[3], decoded_remap.second[0] }; for (u8 channel = 0; channel < 4; channel++) { switch (remapped_inputs[channel]) { default: case CELL_GCM_TEXTURE_REMAP_REMAP: break; case CELL_GCM_TEXTURE_REMAP_ONE: channel_mapping[channel] = D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1; break; case CELL_GCM_TEXTURE_REMAP_ZERO: channel_mapping[channel] = D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0; } } shared_resource_view_desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( channel_mapping[0], channel_mapping[1], channel_mapping[2], channel_mapping[3]); } m_device->CreateShaderResourceView(vram_texture, &shared_resource_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(m_current_texture_descriptors->GetCPUDescriptorHandleForHeapStart()) .Offset((UINT)i, m_descriptor_stride_srv_cbv_uav) ); m_device->CreateSampler(&get_sampler_desc(rsx::method_registers.fragment_textures[i]), CD3DX12_CPU_DESCRIPTOR_HANDLE(m_current_sampler_descriptors->GetCPUDescriptorHandleForHeapStart()) .Offset((UINT)i, m_descriptor_stride_samplers)); } } #endif