void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex) { size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(256); // Scale offset buffer // Separate constant buffer void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + 256)); fill_scale_offset_data(mapped_buffer); int is_alpha_tested = rsx::method_registers.alpha_test_enabled(); u8 alpha_ref_raw = rsx::method_registers.alpha_ref(); float alpha_ref = alpha_ref_raw / 255.f; memcpy((char*)mapped_buffer + 16 * sizeof(float), &is_alpha_tested, sizeof(int)); memcpy((char*)mapped_buffer + 17 * sizeof(float), &alpha_ref, sizeof(float)); f32 fogp0 = rsx::method_registers.fog_params_0(); f32 fogp1 = rsx::method_registers.fog_params_1(); memcpy((char*)mapped_buffer + 18 * sizeof(float), &fogp0, sizeof(float)); memcpy((char*)mapped_buffer + 19 * sizeof(float), &fogp1, sizeof(float)); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + 256)); D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, 256 }; m_device->CreateConstantBufferView(&constant_buffer_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart()) .Offset((INT)descriptorIndex, m_descriptor_stride_srv_cbv_uav)); }
std::tuple<D3D12_INDEX_BUFFER_VIEW, size_t> D3D12GSRender::generate_index_buffer_for_emulated_primitives_array(const std::vector<std::pair<u32, u32> > &vertex_ranges) { size_t index_count = 0; for (const auto &pair : vertex_ranges) index_count += get_index_count(draw_mode, pair.second); // Alloc size_t buffer_size = align(index_count * sizeof(u16), 64); size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); size_t first = 0; for (const auto &pair : vertex_ranges) { size_t element_count = get_index_count(draw_mode, pair.second); write_index_array_for_non_indexed_non_native_primitive_to_buffer((char*)mapped_buffer, draw_mode, (u32)first, (u32)pair.second); mapped_buffer = (char*)mapped_buffer + element_count * sizeof(u16); first += pair.second; } m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); D3D12_INDEX_BUFFER_VIEW index_buffer_view = { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, (UINT)buffer_size, DXGI_FORMAT_R16_UINT }; return std::make_tuple(index_buffer_view, index_count); }
uint64 KGraphicsDevice::QueryTimeStamp(uint32 timestamp_query) { m_TimeStampQueryReadBackRes->Map(0, &CD3DX12_RANGE(0, 0), reinterpret_cast<void**>(&m_TimeStampQueryMem)); uint64 data = ((uint64*)m_TimeStampQueryMem)[timestamp_query]; m_TimeStampQueryReadBackRes->Unmap(0, nullptr); return data; }
void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_index) { size_t buffer_size = 512 * 4 * sizeof(float); size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); fill_vertex_program_constants_data(mapped_buffer); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, (UINT)buffer_size }; m_device->CreateConstantBufferView(&constant_buffer_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart()) .Offset((INT)descriptor_index, m_descriptor_stride_srv_cbv_uav)); }
D3D12_CONSTANT_BUFFER_VIEW_DESC D3D12GSRender::upload_fragment_shader_constants() { // Get constant from fragment program size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(m_fragment_program); // Multiple of 256 never 0 buffer_size = (buffer_size + 255) & ~255; size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); size_t offset = 0; float *mapped_buffer = m_buffer_data.map<float>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); m_pso_cache.fill_fragment_constants_buffer({ mapped_buffer, ::narrow<int>(buffer_size) }, m_fragment_program); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); return { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, (UINT)buffer_size }; }
void D3D12GSRender::upload_and_bind_fragment_shader_constants(size_t descriptor_index) { // Get constant from fragment program size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(m_fragment_program); // Multiple of 256 never 0 buffer_size = (buffer_size + 255) & ~255; size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); size_t offset = 0; float *mapped_buffer = m_buffer_data.map<float>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); m_pso_cache.fill_fragment_constans_buffer({ mapped_buffer, gsl::narrow<int>(buffer_size) }, m_fragment_program); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, (UINT)buffer_size }; m_device->CreateConstantBufferView(&constant_buffer_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(get_current_resource_storage().descriptors_heap->GetCPUDescriptorHandleForHeapStart()) .Offset((INT)descriptor_index, m_descriptor_stride_srv_cbv_uav)); }
// Recalculate vertex positions for the color space triangles and then update the vertex buffer. // The scene's command list must be in the recording state when this method is called. void D3D12HDR::UpdateVertexBuffer() { const XMFLOAT2 primaries709[] = { { 0.64f, 0.33f }, { 0.30f, 0.60f }, { 0.15f, 0.06f }, { 0.3127f, 0.3290f } }; const XMFLOAT2 primaries2020[] = { { 0.708f, 0.292f }, { 0.170f, 0.797f }, { 0.131f, 0.046f }, { 0.3127f, 0.3290f } }; const XMFLOAT2 offset1 = { 0.2f, 0.0f }; const XMFLOAT2 offset2 = { 0.2f, -1.0f }; const XMFLOAT3 triangle709[] = { TransformVertex(primaries709[0], offset1), // R TransformVertex(primaries709[1], offset1), // G TransformVertex(primaries709[2], offset1), // B TransformVertex(primaries709[3], offset1) // White }; const XMFLOAT3 triangle2020[] = { TransformVertex(primaries2020[0], offset2), // R TransformVertex(primaries2020[1], offset2), // G TransformVertex(primaries2020[2], offset2), // B TransformVertex(primaries2020[3], offset2) // White }; TrianglesVertex triangleVertices[] = { // Upper triangles. Rec 709 primaries. { triangle709[2], primaries709[2] }, { triangle709[1], primaries709[1] }, { triangle709[3], primaries709[3] }, { triangle709[1], primaries709[1] }, { triangle709[0], primaries709[0] }, { triangle709[3], primaries709[3] }, { triangle709[0], primaries709[0] }, { triangle709[2], primaries709[2] }, { triangle709[3], primaries709[3] }, // Lower triangles. Rec 2020 primaries. { triangle2020[2], primaries2020[2] }, { triangle2020[1], primaries2020[1] }, { triangle2020[3], primaries2020[3] }, { triangle2020[1], primaries2020[1] }, { triangle2020[0], primaries2020[0] }, { triangle2020[3], primaries2020[3] }, { triangle2020[0], primaries2020[0] }, { triangle2020[2], primaries2020[2] }, { triangle2020[3], primaries2020[3] }, }; // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* mappedUploadHeap = nullptr; ThrowIfFailed(m_vertexBufferUpload->Map(0, &CD3DX12_RANGE(0, 0), reinterpret_cast<void**>(&mappedUploadHeap))); mappedUploadHeap += m_gradientVertexBufferView.SizeInBytes; memcpy(mappedUploadHeap, triangleVertices, sizeof(triangleVertices)); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST)); m_commandList->CopyBufferRegion(m_vertexBuffer.Get(), 0, m_vertexBufferUpload.Get(), 0, m_vertexBuffer->GetDesc().Width); m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); }
// Load the sample assets. void D3D12HDR::LoadAssets() { // Create a root signature containing root constants for brightness information // and the desired output curve as well as a SRV descriptor table pointing to the // intermediate render targets. { CD3DX12_DESCRIPTOR_RANGE ranges[1]; ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 2, 0); CD3DX12_ROOT_PARAMETER rootParameters[2]; rootParameters[0].InitAsConstants(4, 0); rootParameters[1].InitAsDescriptorTable(1, &ranges[0]); D3D12_STATIC_SAMPLER_DESC sampler = {}; sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; sampler.MaxLOD = D3D12_FLOAT32_MAX; sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // Allow input layout and deny uneccessary access to certain pipeline stages. D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS; CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc; rootSignatureDesc.Init(_countof(rootParameters), rootParameters, 1, &sampler, rootSignatureFlags); ComPtr<ID3DBlob> signature; ComPtr<ID3DBlob> error; ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error)); ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature))); } // Create the pipeline state objects for the different views and render target formats // as well as the intermediate blend step. { // Create the pipeline state for the scene geometry. D3D12_INPUT_ELEMENT_DESC gradientElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; // Describe and create the graphics pipeline state objects (PSO). D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.InputLayout = { gradientElementDescs, _countof(gradientElementDescs) }; psoDesc.pRootSignature = m_rootSignature.Get(); psoDesc.VS = CD3DX12_SHADER_BYTECODE(g_gradientVS, sizeof(g_gradientVS)); psoDesc.PS = CD3DX12_SHADER_BYTECODE(g_gradientPS, sizeof(g_gradientPS)); psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); psoDesc.DepthStencilState.DepthEnable = FALSE; psoDesc.DepthStencilState.StencilEnable = FALSE; psoDesc.SampleMask = UINT_MAX; psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; psoDesc.NumRenderTargets = 1; psoDesc.RTVFormats[0] = m_intermediateRenderTargetFormat; psoDesc.SampleDesc.Count = 1; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[GradientPSO]))); // Create pipeline state for the color space triangles. D3D12_INPUT_ELEMENT_DESC colorElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; psoDesc.InputLayout = { colorElementDescs, _countof(colorElementDescs) }; psoDesc.VS = CD3DX12_SHADER_BYTECODE(g_paletteVS, sizeof(g_paletteVS)); psoDesc.PS = CD3DX12_SHADER_BYTECODE(g_palettePS, sizeof(g_palettePS)); psoDesc.RTVFormats[0] = m_intermediateRenderTargetFormat; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[PalettePSO]))); // Create pipeline states for the final blend step. // There will be one for each swap chain format the sample supports. D3D12_INPUT_ELEMENT_DESC quadElementDescs[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }, }; psoDesc.InputLayout = { quadElementDescs, _countof(quadElementDescs) }; psoDesc.VS = CD3DX12_SHADER_BYTECODE(g_presentVS, sizeof(g_presentVS)); psoDesc.PS = CD3DX12_SHADER_BYTECODE(g_presentPS, sizeof(g_presentPS)); psoDesc.RTVFormats[0] = m_swapChainFormats[_8]; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[Present8bitPSO]))); psoDesc.RTVFormats[0] = m_swapChainFormats[_10]; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[Present10bitPSO]))); psoDesc.RTVFormats[0] = m_swapChainFormats[_16]; ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineStates[Present16bitPSO]))); } // Create the command list. ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocators[m_frameIndex].Get(), nullptr, IID_PPV_ARGS(&m_commandList))); // Create the vertex buffer. { // Create geometry for the different sections of the render target. GradientVertex gradientVertices[] = { // Upper strip. SDR Gradient from [0,1]. { { -1.0f, 0.45f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { -1.0f, 0.55f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { 0.0f, 0.45f, 0.0f }, { 1.0f, 1.0f, 1.0f } }, { { 0.0f, 0.55f, 0.0f }, { 1.0f, 1.0f, 1.0f } }, // Lower strip. HDR Gradient from [0,9]. Perceptually, 9.0 is about 3 times as bright as 1.0. (See gradientPS.hlsl.) { { -1.0f, -0.55f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { -1.0f, -0.45f, 0.0f }, { 0.0f, 0.0f, 0.0f } }, { { 0.0f, -0.55f, 0.0f }, { 3.0f, 3.0f, 3.0f } }, { { 0.0f, -0.45f, 0.0f }, { 3.0f, 3.0f, 3.0f } }, }; // The vertices for the color space triangles are dependent on the size of the // render target and will not be loaded at this time. We'll leave a gap in the // buffer that will be filled in later. const UINT triangleVerticesSize = sizeof(TrianglesVertex) * TrianglesVertexCount; m_updateVertexBuffer = true; PresentVertex presentVertices[] = { // 1 triangle that fills the entire render target. { { -1.0f, -3.0f, 0.0f }, { 0.0f, 2.0f } }, // Bottom left { { -1.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } }, // Top left { { 3.0f, 1.0f, 0.0f }, { 2.0f, 0.0f } }, // Top right }; const UINT vertexBufferSize = sizeof(gradientVertices) + triangleVerticesSize + sizeof(presentVertices); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, nullptr, IID_PPV_ARGS(&m_vertexBuffer))); ThrowIfFailed(m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_vertexBufferUpload))); // Copy data to the intermediate upload heap. It will be uploaded to the // DEFAULT buffer when the color space triangle vertices are updated. UINT8* mappedUploadHeap = nullptr; ThrowIfFailed(m_vertexBufferUpload->Map(0, &CD3DX12_RANGE(0, 0), reinterpret_cast<void**>(&mappedUploadHeap))); memcpy(mappedUploadHeap, gradientVertices, sizeof(gradientVertices)); mappedUploadHeap += sizeof(gradientVertices) + triangleVerticesSize; memcpy(mappedUploadHeap, presentVertices, sizeof(presentVertices)); m_vertexBufferUpload->Unmap(0, &CD3DX12_RANGE(0, 0)); // Initialize the vertex buffer views. m_gradientVertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_gradientVertexBufferView.StrideInBytes = sizeof(GradientVertex); m_gradientVertexBufferView.SizeInBytes = sizeof(gradientVertices); m_trianglesVertexBufferView.BufferLocation = m_gradientVertexBufferView.BufferLocation + m_gradientVertexBufferView.SizeInBytes; m_trianglesVertexBufferView.StrideInBytes = sizeof(TrianglesVertex); m_trianglesVertexBufferView.SizeInBytes = triangleVerticesSize; m_presentVertexBufferView.BufferLocation = m_trianglesVertexBufferView.BufferLocation + m_trianglesVertexBufferView.SizeInBytes; m_presentVertexBufferView.StrideInBytes = sizeof(PresentVertex); m_presentVertexBufferView.SizeInBytes = sizeof(presentVertices); } LoadSizeDependentResources(); // Close the command list and execute it to begin the vertex buffer copy into // the default heap. ThrowIfFailed(m_commandList->Close()); ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); // Create synchronization objects and wait until assets have been uploaded to the GPU. { ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence))); m_fenceValues[m_frameIndex]++; // Create an event handle to use for frame synchronization. m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); if (m_fenceEvent == nullptr) { ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError())); } // Wait for the command list to execute; we are reusing the same command // list in our main loop but for now, we just want to wait for setup to // complete before continuing. WaitForGpu(); } }
void D3D12GSRender::flip(int buffer) { ID3D12Resource *resource_to_flip; float viewport_w, viewport_h; if (!is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) { resource_storage &storage = get_current_resource_storage(); assert(storage.ram_framebuffer == nullptr); size_t w = 0, h = 0, row_pitch = 0; size_t offset = 0; if (false) { CellGcmDisplayInfo* buffers = nullptr;// = vm::ps3::_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr); u32 addr = rsx::get_address(gcm_buffers[gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); w = gcm_buffers[gcm_current_buffer].width; h = gcm_buffers[gcm_current_buffer].height; u8 *src_buffer = vm::ps3::_ptr<u8>(addr); row_pitch = align(w * 4, 256); size_t texture_size = row_pitch * h; // * 4 for mipmap levels size_t heap_offset = m_buffer_data.alloc<D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT>(texture_size); void *mapped_buffer = m_buffer_data.map<void>(heap_offset); for (unsigned row = 0; row < h; row++) memcpy((char*)mapped_buffer + row * row_pitch, (char*)src_buffer + row * w * 4, w * 4); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + texture_size)); offset = heap_offset; } CHECK_HRESULT( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, (UINT)w, (UINT)h, 1, 1), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(storage.ram_framebuffer.GetAddressOf()) ) ); get_current_resource_storage().command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(storage.ram_framebuffer.Get(), 0), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(m_buffer_data.get_heap(), { offset, { DXGI_FORMAT_R8G8B8A8_UNORM, (UINT)w, (UINT)h, 1, (UINT)row_pitch } }), nullptr); get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(storage.ram_framebuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ)); resource_to_flip = storage.ram_framebuffer.Get(); viewport_w = (float)w, viewport_h = (float)h; } else { if (std::get<1>(m_rtts.m_bound_render_targets[0]) != nullptr) { get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_render_targets[0]), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); resource_to_flip = std::get<1>(m_rtts.m_bound_render_targets[0]); } else if (std::get<1>(m_rtts.m_bound_render_targets[1]) != nullptr) { get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(std::get<1>(m_rtts.m_bound_render_targets[1]), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); resource_to_flip = std::get<1>(m_rtts.m_bound_render_targets[1]); } else resource_to_flip = nullptr; } get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); D3D12_VIEWPORT viewport = { 0.f, 0.f, (float)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Width, (float)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Height, 0.f, 1.f }; get_current_resource_storage().command_list->RSSetViewports(1, &viewport); D3D12_RECT box = { 0, 0, (LONG)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Width, (LONG)m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()]->GetDesc().Height, }; get_current_resource_storage().command_list->RSSetScissorRects(1, &box); get_current_resource_storage().command_list->SetGraphicsRootSignature(m_output_scaling_pass.root_signature); get_current_resource_storage().command_list->SetPipelineState(m_output_scaling_pass.pso); D3D12_SHADER_RESOURCE_VIEW_DESC shader_resource_view_desc = {}; // FIXME: Not always true shader_resource_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; shader_resource_view_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; shader_resource_view_desc.Texture2D.MipLevels = 1; if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET]))) shader_resource_view_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; else shader_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_3, D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 ); m_device->CreateShaderResourceView(resource_to_flip, &shader_resource_view_desc, CD3DX12_CPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav)); D3D12_SAMPLER_DESC sampler_desc = {}; sampler_desc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_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_output_scaling_pass.sampler_descriptor_heap->GetCPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers)); ID3D12DescriptorHeap *descriptors_heaps[] = { m_output_scaling_pass.texture_descriptor_heap, m_output_scaling_pass.sampler_descriptor_heap }; get_current_resource_storage().command_list->SetDescriptorHeaps(2, descriptors_heaps); get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(0, CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.texture_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_srv_cbv_uav)); get_current_resource_storage().command_list->SetGraphicsRootDescriptorTable(1, CD3DX12_GPU_DESCRIPTOR_HANDLE(m_output_scaling_pass.sampler_descriptor_heap->GetGPUDescriptorHandleForHeapStart()).Offset(m_swap_chain->GetCurrentBackBufferIndex(), m_descriptor_stride_samplers)); get_current_resource_storage().command_list->OMSetRenderTargets(1, &CD3DX12_CPU_DESCRIPTOR_HANDLE(m_backbuffer_descriptor_heap[m_swap_chain->GetCurrentBackBufferIndex()]->GetCPUDescriptorHandleForHeapStart()), true, nullptr); D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view = {}; vertex_buffer_view.BufferLocation = m_output_scaling_pass.vertex_buffer->GetGPUVirtualAddress(); vertex_buffer_view.StrideInBytes = 4 * sizeof(float); vertex_buffer_view.SizeInBytes = 16 * sizeof(float); get_current_resource_storage().command_list->IASetVertexBuffers(0, 1, &vertex_buffer_view); get_current_resource_storage().command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); if (resource_to_flip) get_current_resource_storage().command_list->DrawInstanced(4, 1, 0, 0); if (!rpcs3::config.rsx.d3d12.overlay.value()) get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_backbuffer[m_swap_chain->GetCurrentBackBufferIndex()].Get(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); if (is_flip_surface_in_global_memory(rsx::to_surface_target(rsx::method_registers[NV4097_SET_SURFACE_COLOR_TARGET])) && resource_to_flip != nullptr) get_current_resource_storage().command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(resource_to_flip, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); CHECK_HRESULT(get_current_resource_storage().command_list->Close()); m_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)get_current_resource_storage().command_list.GetAddressOf()); if(rpcs3::config.rsx.d3d12.overlay.value()) render_overlay(); reset_timer(); std::chrono::time_point<std::chrono::system_clock> flip_start = std::chrono::system_clock::now(); CHECK_HRESULT(m_swap_chain->Present(rpcs3::state.config.rsx.vsync.value() ? 1 : 0, 0)); // Add an event signaling queue completion resource_storage &storage = get_non_current_resource_storage(); m_command_queue->Signal(storage.frame_finished_fence.Get(), storage.fence_value); storage.frame_finished_fence->SetEventOnCompletion(storage.fence_value, storage.frame_finished_handle); storage.fence_value++; storage.in_use = true; storage.dirty_textures.merge(m_rtts.invalidated_resources); m_rtts.invalidated_resources.clear(); // Get the put pos - 1. This way after cleaning we can set the get ptr to // this value, allowing heap to proceed even if we cleant before allocating // a new value (that's the reason of the -1) storage.buffer_heap_get_pos = m_buffer_data.get_current_put_pos_minus_one(); storage.readback_heap_get_pos = m_readback_resources.get_current_put_pos_minus_one(); // Now get ready for next frame resource_storage &new_storage = get_current_resource_storage(); new_storage.wait_and_clean(); if (new_storage.in_use) { m_buffer_data.m_get_pos = new_storage.buffer_heap_get_pos; m_readback_resources.m_get_pos = new_storage.readback_heap_get_pos; } m_frame->flip(nullptr); std::chrono::time_point<std::chrono::system_clock> flip_end = std::chrono::system_clock::now(); m_timers.flip_duration += std::chrono::duration_cast<std::chrono::microseconds>(flip_end - flip_start).count(); }
void DX12ClothSimulation::LoadSizeDependentResources() { m_viewport.Width = static_cast<float>( m_width ); m_viewport.Height = static_cast<float>( m_height ); m_viewport.MaxDepth = 1.0f; m_scissorRect.right = static_cast<LONG>( m_width ); m_scissorRect.bottom = static_cast<LONG>( m_height ); // Create frame resources. { CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle( m_rtvHeap->GetCPUDescriptorHandleForHeapStart() ); // Create a RTV for each frame. for ( UINT n = 0; n < FrameCount; n++ ) { ThrowIfFailed( m_swapChain->GetBuffer( n, IID_PPV_ARGS( &m_renderTargets[n] ) ) ); m_device->CreateRenderTargetView( m_renderTargets[n].Get(), nullptr, rtvHandle ); rtvHandle.Offset( 1, m_rtvDescriptorSize ); } } // Create/update the vertex buffer. When updating the vertex buffer it is important // to ensure that the GPU is finished using the resource before it is released. // The OnSizeChanged method waits for the GPU to be idle before this method is // called. { // Define the geometry for a triangle that stays the same size regardless // of the window size. This is not the recommended way to transform vertices. // The same effect could be achieved by using constant buffers and // transforming a static set of vertices in the vertex shader, but this // sample merely demonstrates modifying a resource that is tied to the render // target size. // Other apps might also resize intermediate render targets or depth stencils // at this time. float x = TriangleWidth / m_viewport.Width; float y = TriangleWidth / m_viewport.Height; Vertex triangleVertices[] = { { { 0.0f, y, 0.0f },{ 1.0f, 0.0f, 0.0f, 1.0f } }, { { x, -y, 0.0f },{ 0.0f, 1.0f, 0.0f, 1.0f } }, { { -x, -y, 0.0f },{ 0.0f, 0.0f, 1.0f, 1.0f } } }; const UINT vertexBufferSize = sizeof( triangleVertices ); ThrowIfFailed( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_DEFAULT ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( vertexBufferSize ), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS( &m_vertexBuffer ) ) ); ThrowIfFailed( m_device->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES( D3D12_HEAP_TYPE_UPLOAD ), D3D12_HEAP_FLAG_NONE, &CD3DX12_RESOURCE_DESC::Buffer( vertexBufferSize ), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS( &m_vertexBufferUpload ) ) ); // Copy data to the intermediate upload heap and then schedule a copy // from the upload heap to the vertex buffer. UINT8* pVertexDataBegin; ThrowIfFailed( m_vertexBufferUpload->Map( 0, &CD3DX12_RANGE( 0, vertexBufferSize ), reinterpret_cast<void**>( &pVertexDataBegin ) ) ); memcpy( pVertexDataBegin, triangleVertices, sizeof( triangleVertices ) ); m_vertexBufferUpload->Unmap( 0, nullptr ); m_commandList->CopyBufferRegion( m_vertexBuffer.Get(), 0, m_vertexBufferUpload.Get(), 0, vertexBufferSize ); m_commandList->ResourceBarrier( 1, &CD3DX12_RESOURCE_BARRIER::Transition( m_vertexBuffer.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER ) ); // Initialize the vertex buffer views. m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress(); m_vertexBufferView.StrideInBytes = sizeof( Vertex ); m_vertexBufferView.SizeInBytes = vertexBufferSize; } m_resizeResources = false; }
std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> D3D12GSRender::upload_vertex_attributes( const std::vector<std::pair<u32, u32> > &vertex_ranges, gsl::not_null<ID3D12GraphicsCommandList*> command_list) { std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_views; command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER, D3D12_RESOURCE_STATE_COPY_DEST)); u32 vertex_count = get_vertex_count(vertex_ranges); size_t offset_in_vertex_buffers_buffer = 0; u32 input_mask = rsx::method_registers[NV4097_SET_VERTEX_ATTRIB_INPUT_MASK]; for (int index = 0; index < rsx::limits::vertex_count; ++index) { bool enabled = !!(input_mask & (1 << index)); if (!enabled) continue; if (vertex_arrays_info[index].size > 0) { // Active vertex array const rsx::data_array_format_info &info = vertex_arrays_info[index]; u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size); UINT buffer_size = element_size * vertex_count; size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); for (const auto &range : vertex_ranges) { write_vertex_array_data_to_buffer(mapped_buffer, range.first, range.second, index, info); mapped_buffer = (char*)mapped_buffer + range.second * element_size; } m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size); vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size)); offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16 m_timers.buffer_upload_size += buffer_size; } else if (register_vertex_info[index].size > 0) { // In register vertex attribute const rsx::data_array_format_info &info = register_vertex_info[index]; const std::vector<u8> &data = register_vertex_data[index]; u32 element_size = rsx::get_vertex_type_size_on_host(info.type, info.size); UINT buffer_size = gsl::narrow<UINT>(data.size()); size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); memcpy(mapped_buffer, data.data(), data.size()); m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); command_list->CopyBufferRegion(m_vertex_buffer_data.Get(), offset_in_vertex_buffers_buffer, m_buffer_data.get_heap(), heap_offset, buffer_size); vertex_buffer_views.emplace_back(get_vertex_attribute_srv(info, offset_in_vertex_buffers_buffer, buffer_size)); offset_in_vertex_buffers_buffer = get_next_multiple_of<48>(offset_in_vertex_buffers_buffer + buffer_size); // 48 is multiple of 2, 4, 6, 8, 12, 16 } } command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_vertex_buffer_data.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)); return vertex_buffer_views; }
std::tuple<bool, size_t, std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC>> D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList *command_list) { if (draw_command == rsx::draw_command::inlined_array) { size_t vertex_count; std::vector<D3D12_SHADER_RESOURCE_VIEW_DESC> vertex_buffer_view; std::tie(vertex_buffer_view, vertex_count) = upload_inlined_vertex_array( vertex_arrays_info, { (const gsl::byte*) inline_vertex_array.data(), gsl::narrow<int>(inline_vertex_array.size() * sizeof(uint)) }, m_buffer_data, m_vertex_buffer_data.Get(), command_list); if (is_primitive_native(draw_mode)) return std::make_tuple(false, vertex_count, vertex_buffer_view); D3D12_INDEX_BUFFER_VIEW index_buffer_view; size_t index_count; std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array({ { 0, (u32)vertex_count } }); command_list->IASetIndexBuffer(&index_buffer_view); return std::make_tuple(true, index_count, vertex_buffer_view); } if (draw_command == rsx::draw_command::array) { if (is_primitive_native(draw_mode)) { size_t vertex_count = get_vertex_count(first_count_commands); return std::make_tuple(false, vertex_count, upload_vertex_attributes(first_count_commands, command_list)); } D3D12_INDEX_BUFFER_VIEW index_buffer_view; size_t index_count; std::tie(index_buffer_view, index_count) = generate_index_buffer_for_emulated_primitives_array(first_count_commands); command_list->IASetIndexBuffer(&index_buffer_view); return std::make_tuple(true, index_count, upload_vertex_attributes(first_count_commands, command_list)); } assert(draw_command == rsx::draw_command::indexed); // Index count size_t index_count = get_index_count(draw_mode, gsl::narrow<int>(get_vertex_count(first_count_commands))); rsx::index_array_type indexed_type = rsx::to_index_array_type(rsx::method_registers[NV4097_SET_INDEX_ARRAY_DMA] >> 4); size_t index_size = get_index_type_size(indexed_type); // Alloc size_t buffer_size = align(index_count * index_size, 64); size_t heap_offset = m_buffer_data.alloc<D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT>(buffer_size); void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); u32 min_index, max_index; if (indexed_type == rsx::index_array_type::u16) { gsl::span<u16> dst = { (u16*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) }; std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands); } if (indexed_type == rsx::index_array_type::u32) { gsl::span<u32> dst = { (u32*)mapped_buffer, gsl::narrow<int>(buffer_size / index_size) }; std::tie(min_index, max_index) = write_index_array_data_to_buffer(dst, draw_mode, first_count_commands); } m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size)); D3D12_INDEX_BUFFER_VIEW index_buffer_view = { m_buffer_data.get_heap()->GetGPUVirtualAddress() + heap_offset, (UINT)buffer_size, get_index_type(indexed_type) }; m_timers.buffer_upload_size += buffer_size; command_list->IASetIndexBuffer(&index_buffer_view); return std::make_tuple(true, index_count, upload_vertex_attributes({ std::make_pair(0, max_index + 1) }, command_list)); }