From 69f8571f4336c8e077d4dc322c786466ab362e62 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 2 Jan 2018 17:12:43 +0000 Subject: [PATCH] Remove d3d11_analyse.cpp and merge code in elsewhere * This is temporary until we split up the debug file further, but it makes the D3D11 codebase more consistent with the other APIs. --- renderdoc/driver/d3d11/d3d11_analyse.cpp | 1500 ----------------- renderdoc/driver/d3d11/d3d11_debug.cpp | 1460 ++++++++++++++++ .../driver/d3d11/renderdoc_d3d11.vcxproj | 1 - .../d3d11/renderdoc_d3d11.vcxproj.filters | 3 - 4 files changed, 1460 insertions(+), 1504 deletions(-) delete mode 100644 renderdoc/driver/d3d11/d3d11_analyse.cpp diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp deleted file mode 100644 index 572193091..000000000 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ /dev/null @@ -1,1500 +0,0 @@ -/****************************************************************************** - * The MIT License (MIT) - * - * Copyright (c) 2015-2018 Baldur Karlsson - * Copyright (c) 2014 Crytek - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -#include "data/resource.h" -#include "driver/d3d11/d3d11_renderstate.h" -#include "driver/d3d11/d3d11_resources.h" -#include "driver/shaders/dxbc/dxbc_debug.h" -#include "maths/camera.h" -#include "maths/formatpacking.h" -#include "maths/matrix.h" -#include "maths/vec.h" -#include "serialise/serialiser.h" -#include "strings/string_utils.h" -#include "d3d11_context.h" -#include "d3d11_debug.h" -#include "d3d11_manager.h" - -#include "data/hlsl/debugcbuffers.h" - -void D3D11DebugManager::FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, - const vector &invars, - vector &outvars, const bytebuf &data) -{ - using namespace DXBC; - using namespace ShaderDebug; - - size_t o = offset; - - for(size_t v = 0; v < invars.size(); v++) - { - size_t vec = o + invars[v].descriptor.offset / 16; - size_t comp = (invars[v].descriptor.offset - (invars[v].descriptor.offset & ~0xf)) / 4; - size_t sz = RDCMAX(1U, invars[v].type.descriptor.bytesize / 16); - - offset = vec + sz; - - string basename = prefix + invars[v].name; - - uint32_t rows = invars[v].type.descriptor.rows; - uint32_t cols = invars[v].type.descriptor.cols; - uint32_t elems = RDCMAX(1U, invars[v].type.descriptor.elements); - - if(!invars[v].type.members.empty()) - { - char buf[64] = {0}; - StringFormat::snprintf(buf, 63, "[%d]", elems); - - ShaderVariable var; - var.name = basename; - var.rows = var.columns = 0; - var.type = VarType::Float; - - std::vector varmembers; - - if(elems > 1) - { - for(uint32_t i = 0; i < elems; i++) - { - StringFormat::snprintf(buf, 63, "[%d]", i); - - if(flatten) - { - FillCBufferVariables(basename + buf + ".", vec, flatten, invars[v].type.members, - outvars, data); - } - else - { - ShaderVariable vr; - vr.name = basename + buf; - vr.rows = vr.columns = 0; - vr.type = VarType::Float; - - std::vector mems; - - FillCBufferVariables("", vec, flatten, invars[v].type.members, mems, data); - - vr.isStruct = true; - - vr.members = mems; - - varmembers.push_back(vr); - } - } - - var.isStruct = false; - } - else - { - var.isStruct = true; - - if(flatten) - FillCBufferVariables(basename + ".", vec, flatten, invars[v].type.members, outvars, data); - else - FillCBufferVariables("", vec, flatten, invars[v].type.members, varmembers, data); - } - - if(!flatten) - { - var.members = varmembers; - outvars.push_back(var); - } - - continue; - } - - if(invars[v].type.descriptor.varClass == CLASS_OBJECT || - invars[v].type.descriptor.varClass == CLASS_STRUCT || - invars[v].type.descriptor.varClass == CLASS_INTERFACE_CLASS || - invars[v].type.descriptor.varClass == CLASS_INTERFACE_POINTER) - { - RDCWARN("Unexpected variable '%s' of class '%u' in cbuffer, skipping.", - invars[v].name.c_str(), invars[v].type.descriptor.type); - continue; - } - - size_t elemByteSize = 4; - VarType type = VarType::Float; - switch(invars[v].type.descriptor.type) - { - case VARTYPE_MIN12INT: - case VARTYPE_MIN16INT: - case VARTYPE_INT: type = VarType::Int; break; - case VARTYPE_MIN8FLOAT: - case VARTYPE_MIN10FLOAT: - case VARTYPE_MIN16FLOAT: - case VARTYPE_FLOAT: type = VarType::Float; break; - case VARTYPE_BOOL: - case VARTYPE_UINT: - case VARTYPE_UINT8: - case VARTYPE_MIN16UINT: type = VarType::UInt; break; - case VARTYPE_DOUBLE: - elemByteSize = 8; - type = VarType::Double; - break; - default: - RDCERR("Unexpected type %d for variable '%s' in cbuffer", invars[v].type.descriptor.type, - invars[v].name.c_str()); - } - - bool columnMajor = invars[v].type.descriptor.varClass == CLASS_MATRIX_COLUMNS; - - size_t outIdx = vec; - if(!flatten) - { - outIdx = outvars.size(); - outvars.resize(RDCMAX(outIdx + 1, outvars.size())); - } - else - { - if(columnMajor) - outvars.resize(RDCMAX(outIdx + cols * elems, outvars.size())); - else - outvars.resize(RDCMAX(outIdx + rows * elems, outvars.size())); - } - - size_t dataOffset = vec * sizeof(Vec4f) + comp * sizeof(float); - - if(!outvars[outIdx].name.empty()) - { - RDCASSERT(flatten); - - RDCASSERT(outvars[vec].rows == 1); - RDCASSERT(outvars[vec].columns == comp); - RDCASSERT(rows == 1); - - std::string combinedName = outvars[outIdx].name; - combinedName += ", " + basename; - outvars[outIdx].name = combinedName; - outvars[outIdx].rows = 1; - outvars[outIdx].isStruct = false; - outvars[outIdx].columns += cols; - - if(dataOffset < data.size()) - { - const byte *d = &data[dataOffset]; - - memcpy(&outvars[outIdx].value.uv[comp], d, - RDCMIN(data.size() - dataOffset, elemByteSize * cols)); - } - } - else - { - outvars[outIdx].name = basename; - outvars[outIdx].rows = 1; - outvars[outIdx].type = type; - outvars[outIdx].isStruct = false; - outvars[outIdx].columns = cols; - - ShaderVariable &var = outvars[outIdx]; - - bool isArray = invars[v].type.descriptor.elements > 1; - - if(rows * elems == 1) - { - if(dataOffset < data.size()) - { - const byte *d = &data[dataOffset]; - - memcpy(&outvars[outIdx].value.uv[flatten ? comp : 0], d, - RDCMIN(data.size() - dataOffset, elemByteSize * cols)); - } - } - else if(!isArray && !flatten) - { - outvars[outIdx].rows = rows; - - if(dataOffset < data.size()) - { - const byte *d = &data[dataOffset]; - - RDCASSERT(rows <= 4 && rows * cols <= 16); - - if(columnMajor) - { - uint32_t tmp[16] = {0}; - - // matrices always have 4 columns, for padding reasons (the same reason arrays - // put every element on a new vec4) - for(uint32_t c = 0; c < cols; c++) - { - size_t srcoffs = 4 * elemByteSize * c; - size_t dstoffs = rows * elemByteSize * c; - memcpy((byte *)(tmp) + dstoffs, d + srcoffs, - RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * rows)); - } - - // transpose - for(size_t r = 0; r < rows; r++) - for(size_t c = 0; c < cols; c++) - outvars[outIdx].value.uv[r * cols + c] = tmp[c * rows + r]; - } - else // CLASS_MATRIX_ROWS or other data not to transpose. - { - // matrices always have 4 columns, for padding reasons (the same reason arrays - // put every element on a new vec4) - for(uint32_t r = 0; r < rows; r++) - { - size_t srcoffs = 4 * elemByteSize * r; - size_t dstoffs = cols * elemByteSize * r; - memcpy((byte *)(&outvars[outIdx].value.uv[0]) + dstoffs, d + srcoffs, - RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * cols)); - } - } - } - } - else if(rows * elems > 1) - { - char buf[64] = {0}; - - var.name = outvars[outIdx].name; - - std::vector varmembers; - std::vector *out = &outvars; - size_t rowCopy = 1; - - uint32_t registers = rows; - uint32_t regLen = cols; - const char *regName = "row"; - - std::string base = outvars[outIdx].name; - - if(!flatten) - { - var.rows = 0; - var.columns = 0; - outIdx = 0; - out = &varmembers; - varmembers.resize(elems); - rowCopy = rows; - rows = 1; - registers = 1; - } - else - { - if(columnMajor) - { - registers = cols; - regLen = rows; - regName = "col"; - } - } - - size_t rowDataOffset = vec * sizeof(Vec4f); - - for(size_t r = 0; r < registers * elems; r++) - { - if(isArray && registers > 1) - StringFormat::snprintf(buf, 63, "[%d].%s%d", r / registers, regName, r % registers); - else if(registers > 1) - StringFormat::snprintf(buf, 63, ".%s%d", regName, r); - else - StringFormat::snprintf(buf, 63, "[%d]", r); - - (*out)[outIdx + r].name = base + buf; - (*out)[outIdx + r].rows = (uint32_t)rowCopy; - (*out)[outIdx + r].type = type; - (*out)[outIdx + r].isStruct = false; - (*out)[outIdx + r].columns = regLen; - - size_t totalSize = 0; - - if(flatten) - { - totalSize = elemByteSize * regLen; - } - else - { - // in a matrix, each major element before the last takes up a full - // vec4 at least - size_t vecSize = elemByteSize * 4; - - if(columnMajor) - totalSize = vecSize * (cols - 1) + elemByteSize * rowCopy; - else - totalSize = vecSize * (rowCopy - 1) + elemByteSize * cols; - } - - if((rowDataOffset % sizeof(Vec4f) != 0) && - (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + totalSize) / sizeof(Vec4f))) - { - rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); - } - - // arrays are also aligned to the nearest Vec4f for each element - if(!flatten && isArray) - { - rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); - } - - if(rowDataOffset < data.size()) - { - const byte *d = &data[rowDataOffset]; - - memcpy(&((*out)[outIdx + r].value.uv[0]), d, - RDCMIN(data.size() - rowDataOffset, totalSize)); - - if(!flatten && columnMajor) - { - ShaderVariable tmp = (*out)[outIdx + r]; - - size_t transposeRows = rowCopy > 1 ? 4 : 1; - - // transpose - for(size_t ri = 0; ri < transposeRows; ri++) - for(size_t ci = 0; ci < cols; ci++) - (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * transposeRows + ri]; - } - } - - if(flatten) - { - rowDataOffset += sizeof(Vec4f); - } - else - { - if(columnMajor) - rowDataOffset += sizeof(Vec4f) * (cols - 1) + sizeof(float) * rowCopy; - else - rowDataOffset += sizeof(Vec4f) * (rowCopy - 1) + sizeof(float) * cols; - } - } - - if(!flatten) - { - var.isStruct = false; - var.members = varmembers; - } - } - } - } -} - -void D3D11DebugManager::FillCBufferVariables(const vector &invars, - vector &outvars, bool flattenVec4s, - const bytebuf &data) -{ - size_t zero = 0; - - vector v; - FillCBufferVariables("", zero, flattenVec4s, invars, v, data); - - outvars.reserve(v.size()); - for(size_t i = 0; i < v.size(); i++) - outvars.push_back(v[i]); -} - -uint32_t D3D11DebugManager::PickVertex(uint32_t eventId, const MeshDisplay &cfg, uint32_t x, - uint32_t y) -{ - if(cfg.position.numIndices == 0) - return ~0U; - - D3D11RenderStateTracker tracker(m_WrappedContext); - - struct MeshPickData - { - Vec3f RayPos; - uint32_t PickIdx; - - Vec3f RayDir; - uint32_t PickNumVerts; - - Vec2f PickCoords; - Vec2f PickViewport; - - uint32_t MeshMode; - uint32_t PickUnproject; - Vec2f Padding; - - Matrix4f PickMVP; - - } cbuf; - - cbuf.PickCoords = Vec2f((float)x, (float)y); - cbuf.PickViewport = Vec2f((float)GetWidth(), (float)GetHeight()); - cbuf.PickIdx = cfg.position.indexByteStride ? 1 : 0; - cbuf.PickNumVerts = cfg.position.numIndices; - cbuf.PickUnproject = cfg.position.unproject ? 1 : 0; - - Matrix4f projMat = - Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth()) / float(GetHeight())); - - Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); - - Matrix4f pickMVP = projMat.Mul(camMat); - - Matrix4f pickMVPProj; - if(cfg.position.unproject) - { - // the derivation of the projection matrix might not be right (hell, it could be an - // orthographic projection). But it'll be close enough likely. - Matrix4f guessProj = - cfg.position.farPlane != FLT_MAX - ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) - : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); - - if(cfg.ortho) - guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); - - pickMVPProj = projMat.Mul(camMat.Mul(guessProj.Inverse())); - } - - Vec3f rayPos; - Vec3f rayDir; - // convert mouse pos to world space ray - { - Matrix4f inversePickMVP = pickMVP.Inverse(); - - float pickX = ((float)x) / ((float)GetWidth()); - float pickXCanonical = RDCLERP(-1.0f, 1.0f, pickX); - - float pickY = ((float)y) / ((float)GetHeight()); - // flip the Y axis - float pickYCanonical = RDCLERP(1.0f, -1.0f, pickY); - - Vec3f cameraToWorldNearPosition = - inversePickMVP.Transform(Vec3f(pickXCanonical, pickYCanonical, -1), 1); - - Vec3f cameraToWorldFarPosition = - inversePickMVP.Transform(Vec3f(pickXCanonical, pickYCanonical, 1), 1); - - Vec3f testDir = (cameraToWorldFarPosition - cameraToWorldNearPosition); - testDir.Normalise(); - - // Calculate the ray direction first in the regular way (above), so we can use the - // the output for testing if the ray we are picking is negative or not. This is similar - // to checking against the forward direction of the camera, but more robust - if(cfg.position.unproject) - { - Matrix4f inversePickMVPGuess = pickMVPProj.Inverse(); - - Vec3f nearPosProj = inversePickMVPGuess.Transform(Vec3f(pickXCanonical, pickYCanonical, -1), 1); - - Vec3f farPosProj = inversePickMVPGuess.Transform(Vec3f(pickXCanonical, pickYCanonical, 1), 1); - - rayDir = (farPosProj - nearPosProj); - rayDir.Normalise(); - - if(testDir.z < 0) - { - rayDir = -rayDir; - } - rayPos = nearPosProj; - } - else - { - rayDir = testDir; - rayPos = cameraToWorldNearPosition; - } - } - - cbuf.RayPos = rayPos; - cbuf.RayDir = rayDir; - - cbuf.PickMVP = cfg.position.unproject ? pickMVPProj : pickMVP; - - bool isTriangleMesh = true; - switch(cfg.position.topology) - { - case Topology::TriangleList: - { - cbuf.MeshMode = MESH_TRIANGLE_LIST; - break; - } - case Topology::TriangleStrip: - { - cbuf.MeshMode = MESH_TRIANGLE_STRIP; - break; - } - case Topology::TriangleList_Adj: - { - cbuf.MeshMode = MESH_TRIANGLE_LIST_ADJ; - break; - } - case Topology::TriangleStrip_Adj: - { - cbuf.MeshMode = MESH_TRIANGLE_STRIP_ADJ; - break; - } - default: // points, lines, patchlists, unknown - { - cbuf.MeshMode = MESH_OTHER; - isTriangleMesh = false; - } - } - - ID3D11Buffer *vb = NULL, *ib = NULL; - DXGI_FORMAT ifmt = cfg.position.indexByteStride == 4 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; - - { - auto it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.vertexResourceId); - - if(it != WrappedID3D11Buffer::m_BufferList.end()) - vb = it->second.m_Buffer; - - it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.indexResourceId); - - if(it != WrappedID3D11Buffer::m_BufferList.end()) - ib = it->second.m_Buffer; - } - - HRESULT hr = S_OK; - - // most IB/VBs will not be available as SRVs. So, we copy into our own buffers. - // In the case of VB we also tightly pack and unpack the data. IB can just be - // read as R16 or R32 via the SRV so it is just a straight copy - - if(cfg.position.indexByteStride) - { - // resize up on demand - if(m_DebugRender.PickIBBuf == NULL || - m_DebugRender.PickIBSize < cfg.position.numIndices * cfg.position.indexByteStride) - { - SAFE_RELEASE(m_DebugRender.PickIBBuf); - SAFE_RELEASE(m_DebugRender.PickIBSRV); - - D3D11_BUFFER_DESC desc = {cfg.position.numIndices * cfg.position.indexByteStride, - D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, - 0, - 0, - 0}; - - m_DebugRender.PickIBSize = cfg.position.numIndices * cfg.position.indexByteStride; - - hr = m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.PickIBBuf); - - if(FAILED(hr)) - { - RDCERR("Failed to create PickIBBuf HRESULT: %s", ToStr(hr).c_str()); - return ~0U; - } - - D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; - sdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - sdesc.Format = ifmt; - sdesc.Buffer.FirstElement = 0; - sdesc.Buffer.NumElements = cfg.position.numIndices; - - hr = m_pDevice->CreateShaderResourceView(m_DebugRender.PickIBBuf, &sdesc, - &m_DebugRender.PickIBSRV); - - if(FAILED(hr)) - { - SAFE_RELEASE(m_DebugRender.PickIBBuf); - RDCERR("Failed to create PickIBSRV HRESULT: %s", ToStr(hr).c_str()); - return ~0U; - } - } - - // copy index data as-is, the view format will take care of the rest - - RDCASSERT(cfg.position.indexByteOffset < 0xffffffff); - - if(ib) - { - D3D11_BUFFER_DESC ibdesc; - ib->GetDesc(&ibdesc); - - D3D11_BOX box; - box.front = 0; - box.back = 1; - box.left = (uint32_t)cfg.position.indexByteOffset; - box.right = (uint32_t)cfg.position.indexByteOffset + - cfg.position.numIndices * cfg.position.indexByteStride; - box.top = 0; - box.bottom = 1; - - box.right = RDCMIN(box.right, ibdesc.ByteWidth - (uint32_t)cfg.position.indexByteOffset); - - m_pImmediateContext->CopySubresourceRegion(m_DebugRender.PickIBBuf, 0, 0, 0, 0, ib, 0, &box); - } - } - - if(m_DebugRender.PickVBBuf == NULL || - m_DebugRender.PickVBSize < cfg.position.numIndices * sizeof(Vec4f)) - { - SAFE_RELEASE(m_DebugRender.PickVBBuf); - SAFE_RELEASE(m_DebugRender.PickVBSRV); - - D3D11_BUFFER_DESC desc = {cfg.position.numIndices * sizeof(Vec4f), - D3D11_USAGE_DEFAULT, - D3D11_BIND_SHADER_RESOURCE, - 0, - 0, - 0}; - - m_DebugRender.PickVBSize = cfg.position.numIndices * sizeof(Vec4f); - - hr = m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.PickVBBuf); - - if(FAILED(hr)) - { - RDCERR("Failed to create PickVBBuf HRESULT: %s", ToStr(hr).c_str()); - return ~0U; - } - - D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; - sdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - sdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; - sdesc.Buffer.FirstElement = 0; - sdesc.Buffer.NumElements = cfg.position.numIndices; - - hr = m_pDevice->CreateShaderResourceView(m_DebugRender.PickVBBuf, &sdesc, - &m_DebugRender.PickVBSRV); - - if(FAILED(hr)) - { - SAFE_RELEASE(m_DebugRender.PickVBBuf); - RDCERR("Failed to create PickVBSRV HRESULT: %s", ToStr(hr).c_str()); - return ~0U; - } - } - - // unpack and linearise the data - if(vb) - { - FloatVector *vbData = new FloatVector[cfg.position.numIndices]; - - bytebuf oldData; - GetBufferData(vb, cfg.position.vertexByteOffset, 0, oldData); - - byte *data = &oldData[0]; - byte *dataEnd = data + oldData.size(); - - bool valid; - - uint32_t idxclamp = 0; - if(cfg.position.baseVertex < 0) - idxclamp = uint32_t(-cfg.position.baseVertex); - - for(uint32_t i = 0; i < cfg.position.numIndices; i++) - { - uint32_t idx = i; - - // apply baseVertex but clamp to 0 (don't allow index to become negative) - if(idx < idxclamp) - idx = 0; - else if(cfg.position.baseVertex < 0) - idx -= idxclamp; - else if(cfg.position.baseVertex > 0) - idx += cfg.position.baseVertex; - - vbData[i] = HighlightCache::InterpretVertex(data, idx, cfg, dataEnd, valid); - } - - D3D11_BOX box; - box.top = 0; - box.bottom = 1; - box.front = 0; - box.back = 1; - box.left = 0; - box.right = cfg.position.numIndices * sizeof(Vec4f); - - m_pImmediateContext->UpdateSubresource(m_DebugRender.PickVBBuf, 0, &box, vbData, sizeof(Vec4f), - sizeof(Vec4f)); - - delete[] vbData; - } - - ID3D11ShaderResourceView *srvs[2] = {m_DebugRender.PickIBSRV, m_DebugRender.PickVBSRV}; - - ID3D11Buffer *buf = MakeCBuffer(&cbuf, sizeof(cbuf)); - - m_pImmediateContext->CSSetConstantBuffers(0, 1, &buf); - - m_pImmediateContext->CSSetShaderResources(0, 2, srvs); - - UINT reset = 0; - m_pImmediateContext->CSSetUnorderedAccessViews(0, 1, &m_DebugRender.PickResultUAV, &reset); - - m_pImmediateContext->CSSetShader(m_DebugRender.MeshPickCS, NULL, 0); - - m_pImmediateContext->Dispatch(cfg.position.numIndices / 1024 + 1, 1, 1); - - m_pImmediateContext->CopyStructureCount(m_DebugRender.histogramBuff, 0, - m_DebugRender.PickResultUAV); - - bytebuf results; - GetBufferData(m_DebugRender.histogramBuff, 0, 0, results); - - uint32_t numResults = *(uint32_t *)&results[0]; - - if(numResults > 0) - { - if(isTriangleMesh) - { - struct PickResult - { - uint32_t vertid; - Vec3f intersectionPoint; - }; - - GetBufferData(m_DebugRender.PickResultBuf, 0, 0, results); - - PickResult *pickResults = (PickResult *)&results[0]; - - PickResult *closest = pickResults; - - // distance from raycast hit to nearest worldspace position of the mouse - float closestPickDistance = (closest->intersectionPoint - rayPos).Length(); - - // min with size of results buffer to protect against overflows - for(uint32_t i = 1; i < RDCMIN((uint32_t)DebugRenderData::maxMeshPicks, numResults); i++) - { - float pickDistance = (pickResults[i].intersectionPoint - rayPos).Length(); - if(pickDistance < closestPickDistance) - { - closest = pickResults + i; - } - } - - return closest->vertid; - } - else - { - struct PickResult - { - uint32_t vertid; - uint32_t idx; - float len; - float depth; - }; - - GetBufferData(m_DebugRender.PickResultBuf, 0, 0, results); - - PickResult *pickResults = (PickResult *)&results[0]; - - PickResult *closest = pickResults; - - // min with size of results buffer to protect against overflows - for(uint32_t i = 1; i < RDCMIN((uint32_t)DebugRenderData::maxMeshPicks, numResults); i++) - { - // We need to keep the picking order consistent in the face - // of random buffer appends, when multiple vertices have the - // identical position (e.g. if UVs or normals are different). - // - // We could do something to try and disambiguate, but it's - // never going to be intuitive, it's just going to flicker - // confusingly. - if(pickResults[i].len < closest->len || - (pickResults[i].len == closest->len && pickResults[i].depth < closest->depth) || - (pickResults[i].len == closest->len && pickResults[i].depth == closest->depth && - pickResults[i].vertid < closest->vertid)) - closest = pickResults + i; - } - - return closest->vertid; - } - } - - return ~0U; -} - -void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, - uint32_t mip, uint32_t sample, CompType typeHint, float pixel[4]) -{ - D3D11RenderStateTracker tracker(m_WrappedContext); - - D3D11MarkerRegion marker("PickPixel"); - - m_pImmediateContext->OMSetRenderTargets(1, &m_DebugRender.PickPixelRT, NULL); - - float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - - m_pImmediateContext->ClearRenderTargetView(m_DebugRender.PickPixelRT, color); - - D3D11_VIEWPORT viewport; - RDCEraseEl(viewport); - - int oldW = GetWidth(), oldH = GetHeight(); - - SetOutputDimensions(100, 100); - - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = 100; - viewport.Height = 100; - - m_pImmediateContext->RSSetViewports(1, &viewport); - - { - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = true; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = sample; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = sliceFace; - texDisplay.rangeMin = 0.0f; - texDisplay.rangeMax = 1.0f; - texDisplay.scale = 1.0f; - texDisplay.resourceId = texture; - texDisplay.typeHint = typeHint; - texDisplay.rawOutput = true; - texDisplay.xOffset = -float(x); - texDisplay.yOffset = -float(y); - - RenderTexture(texDisplay, false); - } - - D3D11_BOX box; - box.front = 0; - box.back = 1; - box.left = 0; - box.right = 1; - box.top = 0; - box.bottom = 1; - - ID3D11Resource *res = NULL; - m_DebugRender.PickPixelRT->GetResource(&res); - - m_pImmediateContext->CopySubresourceRegion(m_DebugRender.PickPixelStageTex, 0, 0, 0, 0, res, 0, - &box); - - SAFE_RELEASE(res); - - D3D11_MAPPED_SUBRESOURCE mapped; - mapped.pData = NULL; - HRESULT hr = - m_pImmediateContext->Map(m_DebugRender.PickPixelStageTex, 0, D3D11_MAP_READ, 0, &mapped); - - if(FAILED(hr)) - { - RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); - } - - float *pix = (float *)mapped.pData; - - if(pix == NULL) - { - RDCERR("Failed to map pick-pixel staging texture."); - } - else - { - pixel[0] = pix[0]; - pixel[1] = pix[1]; - pixel[2] = pix[2]; - pixel[3] = pix[3]; - } - - SetOutputDimensions(oldW, oldH); - - m_pImmediateContext->Unmap(m_DebugRender.PickPixelStageTex, 0); -} - -void D3D11DebugManager::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, - const GetTextureDataParams ¶ms, bytebuf &data) -{ - D3D11RenderStateTracker tracker(m_WrappedContext); - - ID3D11Resource *dummyTex = NULL; - - uint32_t subresource = 0; - uint32_t mips = 0; - - size_t bytesize = 0; - - if(WrappedID3D11Texture1D::m_TextureList.find(tex) != WrappedID3D11Texture1D::m_TextureList.end()) - { - WrappedID3D11Texture1D *wrapTex = - (WrappedID3D11Texture1D *)WrappedID3D11Texture1D::m_TextureList[tex].m_Texture; - - D3D11_TEXTURE1D_DESC desc = {0}; - wrapTex->GetDesc(&desc); - - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.MiscFlags = 0; - desc.Usage = D3D11_USAGE_STAGING; - - ID3D11Texture1D *d = NULL; - - mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, 1, 1); - - if(mip >= mips || arrayIdx >= desc.ArraySize) - return; - - if(params.remap != RemapTexture::NoRemap) - { - RDCASSERT(params.remap == RemapTexture::RGBA8); - - desc.Format = - IsSRGBFormat(desc.Format) ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; - desc.ArraySize = 1; - } - - subresource = arrayIdx * mips + mip; - - HRESULT hr = m_pDevice->CreateTexture1D(&desc, NULL, &d); - - dummyTex = d; - - if(FAILED(hr)) - { - RDCERR("Couldn't create staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); - return; - } - - bytesize = GetByteSize(desc.Width, 1, 1, desc.Format, mip); - - if(params.remap != RemapTexture::NoRemap) - { - RDCASSERT(params.remap == RemapTexture::RGBA8); - - subresource = mip; - - desc.CPUAccessFlags = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_RENDER_TARGET; - - ID3D11Texture1D *rtTex = NULL; - - hr = m_pDevice->CreateTexture1D(&desc, NULL, &rtTex); - - if(FAILED(hr)) - { - RDCERR("Couldn't create target texture to downcast texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - return; - } - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; - rtvDesc.Format = desc.Format; - rtvDesc.Texture1D.MipSlice = mip; - - ID3D11RenderTargetView *wrappedrtv = NULL; - hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); - if(FAILED(hr)) - { - RDCERR("Couldn't create target rtv to downcast texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - SAFE_RELEASE(rtTex); - return; - } - - ID3D11RenderTargetView *rtv = wrappedrtv; - - m_pImmediateContext->OMSetRenderTargets(1, &rtv, NULL); - float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - m_pImmediateContext->ClearRenderTargetView(rtv, color); - - D3D11_VIEWPORT viewport = {0, 0, (float)(desc.Width >> mip), 1.0f, 0.0f, 1.0f}; - - int oldW = GetWidth(), oldH = GetHeight(); - SetOutputDimensions(desc.Width, 1); - m_pImmediateContext->RSSetViewports(1, &viewport); - - { - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = false; - texDisplay.overlay = DebugOverlay::NoOverlay; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = 0; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; - texDisplay.rangeMin = params.blackPoint; - texDisplay.rangeMax = params.whitePoint; - texDisplay.scale = 1.0f; - texDisplay.resourceId = tex; - texDisplay.typeHint = params.typeHint; - texDisplay.rawOutput = false; - texDisplay.xOffset = 0; - texDisplay.yOffset = 0; - - RenderTexture(texDisplay, false); - } - - SetOutputDimensions(oldW, oldH); - - m_pImmediateContext->CopyResource(d, rtTex); - SAFE_RELEASE(rtTex); - - SAFE_RELEASE(wrappedrtv); - } - else - { - m_pImmediateContext->CopyResource(d, wrapTex); - } - } - else if(WrappedID3D11Texture2D1::m_TextureList.find(tex) != - WrappedID3D11Texture2D1::m_TextureList.end()) - { - WrappedID3D11Texture2D1 *wrapTex = - (WrappedID3D11Texture2D1 *)WrappedID3D11Texture2D1::m_TextureList[tex].m_Texture; - - D3D11_TEXTURE2D_DESC desc = {0}; - wrapTex->GetDesc(&desc); - - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.MiscFlags = 0; - desc.Usage = D3D11_USAGE_STAGING; - - bool wasms = false; - - if(desc.SampleDesc.Count > 1) - { - desc.ArraySize *= desc.SampleDesc.Count; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - - wasms = true; - } - - ID3D11Texture2D *d = NULL; - - mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, 1); - - if(mip >= mips || arrayIdx >= desc.ArraySize) - return; - - if(params.remap != RemapTexture::NoRemap) - { - RDCASSERT(params.remap == RemapTexture::RGBA8); - - desc.Format = (IsSRGBFormat(desc.Format) || wrapTex->m_RealDescriptor) - ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB - : DXGI_FORMAT_R8G8B8A8_UNORM; - desc.ArraySize = 1; - } - - subresource = arrayIdx * mips + mip; - - HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &d); - - dummyTex = d; - - if(FAILED(hr)) - { - RDCERR("Couldn't create staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); - return; - } - - bytesize = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); - - if(params.remap != RemapTexture::NoRemap) - { - RDCASSERT(params.remap == RemapTexture::RGBA8); - - subresource = mip; - - desc.CPUAccessFlags = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_RENDER_TARGET; - - ID3D11Texture2D *rtTex = NULL; - - hr = m_pDevice->CreateTexture2D(&desc, NULL, &rtTex); - - if(FAILED(hr)) - { - RDCERR("Couldn't create target texture to downcast texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - return; - } - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Format = desc.Format; - rtvDesc.Texture2D.MipSlice = mip; - - ID3D11RenderTargetView *wrappedrtv = NULL; - hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); - if(FAILED(hr)) - { - RDCERR("Couldn't create target rtv to downcast texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - SAFE_RELEASE(rtTex); - return; - } - - ID3D11RenderTargetView *rtv = wrappedrtv; - - m_pImmediateContext->OMSetRenderTargets(1, &rtv, NULL); - float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - m_pImmediateContext->ClearRenderTargetView(rtv, color); - - D3D11_VIEWPORT viewport = {0, 0, (float)(desc.Width >> mip), (float)(desc.Height >> mip), - 0.0f, 1.0f}; - - int oldW = GetWidth(), oldH = GetHeight(); - SetOutputDimensions(desc.Width, desc.Height); - m_pImmediateContext->RSSetViewports(1, &viewport); - - { - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = false; - texDisplay.overlay = DebugOverlay::NoOverlay; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = params.resolve ? ~0U : arrayIdx; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = arrayIdx; - texDisplay.rangeMin = params.blackPoint; - texDisplay.rangeMax = params.whitePoint; - texDisplay.scale = 1.0f; - texDisplay.resourceId = tex; - texDisplay.typeHint = params.typeHint; - texDisplay.rawOutput = false; - texDisplay.xOffset = 0; - texDisplay.yOffset = 0; - - RenderTexture(texDisplay, false); - } - - SetOutputDimensions(oldW, oldH); - - m_pImmediateContext->CopyResource(d, rtTex); - SAFE_RELEASE(rtTex); - - SAFE_RELEASE(wrappedrtv); - } - else if(wasms && params.resolve) - { - desc.Usage = D3D11_USAGE_DEFAULT; - desc.CPUAccessFlags = 0; - - ID3D11Texture2D *resolveTex = NULL; - - hr = m_pDevice->CreateTexture2D(&desc, NULL, &resolveTex); - - if(FAILED(hr)) - { - RDCERR("Couldn't create target texture to resolve texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - return; - } - - m_pImmediateContext->ResolveSubresource(resolveTex, arrayIdx, wrapTex, arrayIdx, desc.Format); - m_pImmediateContext->CopyResource(d, resolveTex); - - SAFE_RELEASE(resolveTex); - } - else if(wasms) - { - CopyTex2DMSToArray(UNWRAP(WrappedID3D11Texture2D1, d), wrapTex->GetReal()); - } - else - { - m_pImmediateContext->CopyResource(d, wrapTex); - } - } - else if(WrappedID3D11Texture3D1::m_TextureList.find(tex) != - WrappedID3D11Texture3D1::m_TextureList.end()) - { - WrappedID3D11Texture3D1 *wrapTex = - (WrappedID3D11Texture3D1 *)WrappedID3D11Texture3D1::m_TextureList[tex].m_Texture; - - D3D11_TEXTURE3D_DESC desc = {0}; - wrapTex->GetDesc(&desc); - - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.MiscFlags = 0; - desc.Usage = D3D11_USAGE_STAGING; - - ID3D11Texture3D *d = NULL; - - mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, desc.Depth); - - if(mip >= mips) - return; - - if(params.remap != RemapTexture::NoRemap) - { - RDCASSERT(params.remap == RemapTexture::RGBA8); - - desc.Format = - IsSRGBFormat(desc.Format) ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; - } - - subresource = mip; - - HRESULT hr = m_pDevice->CreateTexture3D(&desc, NULL, &d); - - dummyTex = d; - - if(FAILED(hr)) - { - RDCERR("Couldn't create staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); - return; - } - - bytesize = GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, mip); - - if(params.remap != RemapTexture::NoRemap) - { - RDCASSERT(params.remap == RemapTexture::RGBA8); - - subresource = mip; - - desc.CPUAccessFlags = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_RENDER_TARGET; - - ID3D11Texture3D *rtTex = NULL; - - hr = m_pDevice->CreateTexture3D(&desc, NULL, &rtTex); - - if(FAILED(hr)) - { - RDCERR("Couldn't create target texture to downcast texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - return; - } - - D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; - rtvDesc.Format = desc.Format; - rtvDesc.Texture3D.MipSlice = mip; - rtvDesc.Texture3D.FirstWSlice = 0; - rtvDesc.Texture3D.WSize = 1; - ID3D11RenderTargetView *wrappedrtv = NULL; - ID3D11RenderTargetView *rtv = NULL; - - D3D11_VIEWPORT viewport = {0, 0, (float)(desc.Width >> mip), (float)(desc.Height >> mip), - 0.0f, 1.0f}; - - int oldW = GetWidth(), oldH = GetHeight(); - - for(UINT i = 0; i < (desc.Depth >> mip); i++) - { - rtvDesc.Texture3D.FirstWSlice = i; - hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); - if(FAILED(hr)) - { - RDCERR("Couldn't create target rtv to downcast texture. HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(d); - SAFE_RELEASE(rtTex); - return; - } - - rtv = wrappedrtv; - - m_pImmediateContext->OMSetRenderTargets(1, &rtv, NULL); - float color[4] = {0.0f, 0.5f, 0.0f, 0.0f}; - m_pImmediateContext->ClearRenderTargetView(rtv, color); - - SetOutputDimensions(desc.Width, desc.Height); - m_pImmediateContext->RSSetViewports(1, &viewport); - - TextureDisplay texDisplay; - - texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; - texDisplay.hdrMultiplier = -1.0f; - texDisplay.linearDisplayAsGamma = false; - texDisplay.overlay = DebugOverlay::NoOverlay; - texDisplay.flipY = false; - texDisplay.mip = mip; - texDisplay.sampleIdx = 0; - texDisplay.customShaderId = ResourceId(); - texDisplay.sliceFace = i << mip; - texDisplay.rangeMin = params.blackPoint; - texDisplay.rangeMax = params.whitePoint; - texDisplay.scale = 1.0f; - texDisplay.resourceId = tex; - texDisplay.typeHint = params.typeHint; - texDisplay.rawOutput = false; - texDisplay.xOffset = 0; - texDisplay.yOffset = 0; - - RenderTexture(texDisplay, false); - - SAFE_RELEASE(wrappedrtv); - } - - SetOutputDimensions(oldW, oldH); - - m_pImmediateContext->CopyResource(d, rtTex); - SAFE_RELEASE(rtTex); - } - else - { - m_pImmediateContext->CopyResource(d, wrapTex); - } - } - else - { - RDCERR("Trying to get texture data for unknown ID %llu!", tex); - return; - } - - MapIntercept intercept; - - D3D11_MAPPED_SUBRESOURCE mapped = {0}; - HRESULT hr = m_pImmediateContext->Map(dummyTex, subresource, D3D11_MAP_READ, 0, &mapped); - - if(SUCCEEDED(hr)) - { - data.resize(bytesize); - intercept.InitWrappedResource(dummyTex, subresource, data.data()); - intercept.SetD3D(mapped); - intercept.CopyFromD3D(); - - // for 3D textures if we wanted a particular slice (arrayIdx > 0) - // copy it into the beginning. - if(intercept.numSlices > 1 && arrayIdx > 0 && (int)arrayIdx < intercept.numSlices) - { - byte *dst = data.data(); - byte *src = data.data() + intercept.app.DepthPitch * arrayIdx; - - for(int row = 0; row < intercept.numRows; row++) - { - memcpy(dst, src, intercept.app.RowPitch); - - src += intercept.app.RowPitch; - dst += intercept.app.RowPitch; - } - } - } - else - { - RDCERR("Couldn't map staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); - } - - SAFE_RELEASE(dummyTex); -} - -ResourceId D3D11DebugManager::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, - uint32_t arrayIdx, uint32_t sampleIdx, - CompType typeHint) -{ - TextureShaderDetails details = GetShaderDetails(texid, typeHint, false); - - CreateCustomShaderTex(details.texWidth, details.texHeight); - - D3D11RenderStateTracker tracker(m_WrappedContext); - - { - D3D11_RENDER_TARGET_VIEW_DESC desc; - - desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - desc.Texture2D.MipSlice = mip; - - WrappedID3D11Texture2D1 *wrapped = (WrappedID3D11Texture2D1 *)m_CustomShaderTex; - HRESULT hr = m_pDevice->CreateRenderTargetView(wrapped, &desc, &m_CustomShaderRTV); - - if(FAILED(hr)) - { - RDCERR("Failed to create custom shader rtv HRESULT: %s", ToStr(hr).c_str()); - return m_CustomShaderResourceId; - } - } - - m_pImmediateContext->OMSetRenderTargets(1, &m_CustomShaderRTV, NULL); - - float clr[] = {0.0f, 0.0f, 0.0f, 0.0f}; - m_pImmediateContext->ClearRenderTargetView(m_CustomShaderRTV, clr); - - D3D11_VIEWPORT viewport; - RDCEraseEl(viewport); - - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = (float)RDCMAX(1U, details.texWidth >> mip); - viewport.Height = (float)RDCMAX(1U, details.texHeight >> mip); - - m_pImmediateContext->RSSetViewports(1, &viewport); - - TextureDisplay disp; - disp.red = disp.green = disp.blue = disp.alpha = true; - disp.flipY = false; - disp.xOffset = 0.0f; - disp.yOffset = 0.0f; - disp.customShaderId = shader; - disp.resourceId = texid; - disp.typeHint = typeHint; - disp.backgroundColor = FloatVector(0, 0, 0, 1.0); - disp.hdrMultiplier = -1.0f; - disp.linearDisplayAsGamma = false; - disp.mip = mip; - disp.sampleIdx = sampleIdx; - disp.overlay = DebugOverlay::NoOverlay; - disp.rangeMin = 0.0f; - disp.rangeMax = 1.0f; - disp.rawOutput = false; - disp.scale = 1.0f; - disp.sliceFace = arrayIdx; - - SetOutputDimensions(RDCMAX(1U, details.texWidth >> mip), RDCMAX(1U, details.texHeight >> mip)); - - RenderTexture(disp, true); - - return m_CustomShaderResourceId; -} - -void D3D11DebugManager::CreateCustomShaderTex(uint32_t w, uint32_t h) -{ - D3D11_TEXTURE2D_DESC texdesc; - - texdesc.ArraySize = 1; - texdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; - texdesc.CPUAccessFlags = 0; - texdesc.MipLevels = CalcNumMips((int)w, (int)h, 1); - texdesc.MiscFlags = 0; - texdesc.SampleDesc.Count = 1; - texdesc.SampleDesc.Quality = 0; - texdesc.Usage = D3D11_USAGE_DEFAULT; - texdesc.Width = w; - texdesc.Height = h; - texdesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - - if(m_CustomShaderTex) - { - D3D11_TEXTURE2D_DESC customTexDesc; - m_CustomShaderTex->GetDesc(&customTexDesc); - - if(customTexDesc.Width == w && customTexDesc.Height == h) - return; - - SAFE_RELEASE(m_CustomShaderRTV); - SAFE_RELEASE(m_CustomShaderTex); - } - - HRESULT hr = m_pDevice->CreateTexture2D(&texdesc, NULL, &m_CustomShaderTex); - - if(FAILED(hr)) - { - RDCERR("Failed to create custom shader tex HRESULT: %s", ToStr(hr).c_str()); - } - else - { - m_CustomShaderResourceId = GetIDForResource(m_CustomShaderTex); - } -} diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 6c3fb55ff..5ef8fab11 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -4386,3 +4386,1463 @@ void D3D11DebugManager::RenderMesh(uint32_t eventId, const vector &s m_pImmediateContext->Draw(24, 0); } } + +void D3D11DebugManager::FillCBufferVariables(const string &prefix, size_t &offset, bool flatten, + const vector &invars, + vector &outvars, const bytebuf &data) +{ + using namespace DXBC; + using namespace ShaderDebug; + + size_t o = offset; + + for(size_t v = 0; v < invars.size(); v++) + { + size_t vec = o + invars[v].descriptor.offset / 16; + size_t comp = (invars[v].descriptor.offset - (invars[v].descriptor.offset & ~0xf)) / 4; + size_t sz = RDCMAX(1U, invars[v].type.descriptor.bytesize / 16); + + offset = vec + sz; + + string basename = prefix + invars[v].name; + + uint32_t rows = invars[v].type.descriptor.rows; + uint32_t cols = invars[v].type.descriptor.cols; + uint32_t elems = RDCMAX(1U, invars[v].type.descriptor.elements); + + if(!invars[v].type.members.empty()) + { + char buf[64] = {0}; + StringFormat::snprintf(buf, 63, "[%d]", elems); + + ShaderVariable var; + var.name = basename; + var.rows = var.columns = 0; + var.type = VarType::Float; + + std::vector varmembers; + + if(elems > 1) + { + for(uint32_t i = 0; i < elems; i++) + { + StringFormat::snprintf(buf, 63, "[%d]", i); + + if(flatten) + { + FillCBufferVariables(basename + buf + ".", vec, flatten, invars[v].type.members, + outvars, data); + } + else + { + ShaderVariable vr; + vr.name = basename + buf; + vr.rows = vr.columns = 0; + vr.type = VarType::Float; + + std::vector mems; + + FillCBufferVariables("", vec, flatten, invars[v].type.members, mems, data); + + vr.isStruct = true; + + vr.members = mems; + + varmembers.push_back(vr); + } + } + + var.isStruct = false; + } + else + { + var.isStruct = true; + + if(flatten) + FillCBufferVariables(basename + ".", vec, flatten, invars[v].type.members, outvars, data); + else + FillCBufferVariables("", vec, flatten, invars[v].type.members, varmembers, data); + } + + if(!flatten) + { + var.members = varmembers; + outvars.push_back(var); + } + + continue; + } + + if(invars[v].type.descriptor.varClass == CLASS_OBJECT || + invars[v].type.descriptor.varClass == CLASS_STRUCT || + invars[v].type.descriptor.varClass == CLASS_INTERFACE_CLASS || + invars[v].type.descriptor.varClass == CLASS_INTERFACE_POINTER) + { + RDCWARN("Unexpected variable '%s' of class '%u' in cbuffer, skipping.", + invars[v].name.c_str(), invars[v].type.descriptor.type); + continue; + } + + size_t elemByteSize = 4; + VarType type = VarType::Float; + switch(invars[v].type.descriptor.type) + { + case VARTYPE_MIN12INT: + case VARTYPE_MIN16INT: + case VARTYPE_INT: type = VarType::Int; break; + case VARTYPE_MIN8FLOAT: + case VARTYPE_MIN10FLOAT: + case VARTYPE_MIN16FLOAT: + case VARTYPE_FLOAT: type = VarType::Float; break; + case VARTYPE_BOOL: + case VARTYPE_UINT: + case VARTYPE_UINT8: + case VARTYPE_MIN16UINT: type = VarType::UInt; break; + case VARTYPE_DOUBLE: + elemByteSize = 8; + type = VarType::Double; + break; + default: + RDCERR("Unexpected type %d for variable '%s' in cbuffer", invars[v].type.descriptor.type, + invars[v].name.c_str()); + } + + bool columnMajor = invars[v].type.descriptor.varClass == CLASS_MATRIX_COLUMNS; + + size_t outIdx = vec; + if(!flatten) + { + outIdx = outvars.size(); + outvars.resize(RDCMAX(outIdx + 1, outvars.size())); + } + else + { + if(columnMajor) + outvars.resize(RDCMAX(outIdx + cols * elems, outvars.size())); + else + outvars.resize(RDCMAX(outIdx + rows * elems, outvars.size())); + } + + size_t dataOffset = vec * sizeof(Vec4f) + comp * sizeof(float); + + if(!outvars[outIdx].name.empty()) + { + RDCASSERT(flatten); + + RDCASSERT(outvars[vec].rows == 1); + RDCASSERT(outvars[vec].columns == comp); + RDCASSERT(rows == 1); + + std::string combinedName = outvars[outIdx].name; + combinedName += ", " + basename; + outvars[outIdx].name = combinedName; + outvars[outIdx].rows = 1; + outvars[outIdx].isStruct = false; + outvars[outIdx].columns += cols; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&outvars[outIdx].value.uv[comp], d, + RDCMIN(data.size() - dataOffset, elemByteSize * cols)); + } + } + else + { + outvars[outIdx].name = basename; + outvars[outIdx].rows = 1; + outvars[outIdx].type = type; + outvars[outIdx].isStruct = false; + outvars[outIdx].columns = cols; + + ShaderVariable &var = outvars[outIdx]; + + bool isArray = invars[v].type.descriptor.elements > 1; + + if(rows * elems == 1) + { + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + memcpy(&outvars[outIdx].value.uv[flatten ? comp : 0], d, + RDCMIN(data.size() - dataOffset, elemByteSize * cols)); + } + } + else if(!isArray && !flatten) + { + outvars[outIdx].rows = rows; + + if(dataOffset < data.size()) + { + const byte *d = &data[dataOffset]; + + RDCASSERT(rows <= 4 && rows * cols <= 16); + + if(columnMajor) + { + uint32_t tmp[16] = {0}; + + // matrices always have 4 columns, for padding reasons (the same reason arrays + // put every element on a new vec4) + for(uint32_t c = 0; c < cols; c++) + { + size_t srcoffs = 4 * elemByteSize * c; + size_t dstoffs = rows * elemByteSize * c; + memcpy((byte *)(tmp) + dstoffs, d + srcoffs, + RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * rows)); + } + + // transpose + for(size_t r = 0; r < rows; r++) + for(size_t c = 0; c < cols; c++) + outvars[outIdx].value.uv[r * cols + c] = tmp[c * rows + r]; + } + else // CLASS_MATRIX_ROWS or other data not to transpose. + { + // matrices always have 4 columns, for padding reasons (the same reason arrays + // put every element on a new vec4) + for(uint32_t r = 0; r < rows; r++) + { + size_t srcoffs = 4 * elemByteSize * r; + size_t dstoffs = cols * elemByteSize * r; + memcpy((byte *)(&outvars[outIdx].value.uv[0]) + dstoffs, d + srcoffs, + RDCMIN(data.size() - dataOffset + srcoffs, elemByteSize * cols)); + } + } + } + } + else if(rows * elems > 1) + { + char buf[64] = {0}; + + var.name = outvars[outIdx].name; + + std::vector varmembers; + std::vector *out = &outvars; + size_t rowCopy = 1; + + uint32_t registers = rows; + uint32_t regLen = cols; + const char *regName = "row"; + + std::string base = outvars[outIdx].name; + + if(!flatten) + { + var.rows = 0; + var.columns = 0; + outIdx = 0; + out = &varmembers; + varmembers.resize(elems); + rowCopy = rows; + rows = 1; + registers = 1; + } + else + { + if(columnMajor) + { + registers = cols; + regLen = rows; + regName = "col"; + } + } + + size_t rowDataOffset = vec * sizeof(Vec4f); + + for(size_t r = 0; r < registers * elems; r++) + { + if(isArray && registers > 1) + StringFormat::snprintf(buf, 63, "[%d].%s%d", r / registers, regName, r % registers); + else if(registers > 1) + StringFormat::snprintf(buf, 63, ".%s%d", regName, r); + else + StringFormat::snprintf(buf, 63, "[%d]", r); + + (*out)[outIdx + r].name = base + buf; + (*out)[outIdx + r].rows = (uint32_t)rowCopy; + (*out)[outIdx + r].type = type; + (*out)[outIdx + r].isStruct = false; + (*out)[outIdx + r].columns = regLen; + + size_t totalSize = 0; + + if(flatten) + { + totalSize = elemByteSize * regLen; + } + else + { + // in a matrix, each major element before the last takes up a full + // vec4 at least + size_t vecSize = elemByteSize * 4; + + if(columnMajor) + totalSize = vecSize * (cols - 1) + elemByteSize * rowCopy; + else + totalSize = vecSize * (rowCopy - 1) + elemByteSize * cols; + } + + if((rowDataOffset % sizeof(Vec4f) != 0) && + (rowDataOffset / sizeof(Vec4f) != (rowDataOffset + totalSize) / sizeof(Vec4f))) + { + rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); + } + + // arrays are also aligned to the nearest Vec4f for each element + if(!flatten && isArray) + { + rowDataOffset = AlignUp(rowDataOffset, sizeof(Vec4f)); + } + + if(rowDataOffset < data.size()) + { + const byte *d = &data[rowDataOffset]; + + memcpy(&((*out)[outIdx + r].value.uv[0]), d, + RDCMIN(data.size() - rowDataOffset, totalSize)); + + if(!flatten && columnMajor) + { + ShaderVariable tmp = (*out)[outIdx + r]; + + size_t transposeRows = rowCopy > 1 ? 4 : 1; + + // transpose + for(size_t ri = 0; ri < transposeRows; ri++) + for(size_t ci = 0; ci < cols; ci++) + (*out)[outIdx + r].value.uv[ri * cols + ci] = tmp.value.uv[ci * transposeRows + ri]; + } + } + + if(flatten) + { + rowDataOffset += sizeof(Vec4f); + } + else + { + if(columnMajor) + rowDataOffset += sizeof(Vec4f) * (cols - 1) + sizeof(float) * rowCopy; + else + rowDataOffset += sizeof(Vec4f) * (rowCopy - 1) + sizeof(float) * cols; + } + } + + if(!flatten) + { + var.isStruct = false; + var.members = varmembers; + } + } + } + } +} + +void D3D11DebugManager::FillCBufferVariables(const vector &invars, + vector &outvars, bool flattenVec4s, + const bytebuf &data) +{ + size_t zero = 0; + + vector v; + FillCBufferVariables("", zero, flattenVec4s, invars, v, data); + + outvars.reserve(v.size()); + for(size_t i = 0; i < v.size(); i++) + outvars.push_back(v[i]); +} + +uint32_t D3D11DebugManager::PickVertex(uint32_t eventId, const MeshDisplay &cfg, uint32_t x, + uint32_t y) +{ + if(cfg.position.numIndices == 0) + return ~0U; + + D3D11RenderStateTracker tracker(m_WrappedContext); + + struct MeshPickData + { + Vec3f RayPos; + uint32_t PickIdx; + + Vec3f RayDir; + uint32_t PickNumVerts; + + Vec2f PickCoords; + Vec2f PickViewport; + + uint32_t MeshMode; + uint32_t PickUnproject; + Vec2f Padding; + + Matrix4f PickMVP; + + } cbuf; + + cbuf.PickCoords = Vec2f((float)x, (float)y); + cbuf.PickViewport = Vec2f((float)GetWidth(), (float)GetHeight()); + cbuf.PickIdx = cfg.position.indexByteStride ? 1 : 0; + cbuf.PickNumVerts = cfg.position.numIndices; + cbuf.PickUnproject = cfg.position.unproject ? 1 : 0; + + Matrix4f projMat = + Matrix4f::Perspective(90.0f, 0.1f, 100000.0f, float(GetWidth()) / float(GetHeight())); + + Matrix4f camMat = cfg.cam ? ((Camera *)cfg.cam)->GetMatrix() : Matrix4f::Identity(); + + Matrix4f pickMVP = projMat.Mul(camMat); + + Matrix4f pickMVPProj; + if(cfg.position.unproject) + { + // the derivation of the projection matrix might not be right (hell, it could be an + // orthographic projection). But it'll be close enough likely. + Matrix4f guessProj = + cfg.position.farPlane != FLT_MAX + ? Matrix4f::Perspective(cfg.fov, cfg.position.nearPlane, cfg.position.farPlane, cfg.aspect) + : Matrix4f::ReversePerspective(cfg.fov, cfg.position.nearPlane, cfg.aspect); + + if(cfg.ortho) + guessProj = Matrix4f::Orthographic(cfg.position.nearPlane, cfg.position.farPlane); + + pickMVPProj = projMat.Mul(camMat.Mul(guessProj.Inverse())); + } + + Vec3f rayPos; + Vec3f rayDir; + // convert mouse pos to world space ray + { + Matrix4f inversePickMVP = pickMVP.Inverse(); + + float pickX = ((float)x) / ((float)GetWidth()); + float pickXCanonical = RDCLERP(-1.0f, 1.0f, pickX); + + float pickY = ((float)y) / ((float)GetHeight()); + // flip the Y axis + float pickYCanonical = RDCLERP(1.0f, -1.0f, pickY); + + Vec3f cameraToWorldNearPosition = + inversePickMVP.Transform(Vec3f(pickXCanonical, pickYCanonical, -1), 1); + + Vec3f cameraToWorldFarPosition = + inversePickMVP.Transform(Vec3f(pickXCanonical, pickYCanonical, 1), 1); + + Vec3f testDir = (cameraToWorldFarPosition - cameraToWorldNearPosition); + testDir.Normalise(); + + // Calculate the ray direction first in the regular way (above), so we can use the + // the output for testing if the ray we are picking is negative or not. This is similar + // to checking against the forward direction of the camera, but more robust + if(cfg.position.unproject) + { + Matrix4f inversePickMVPGuess = pickMVPProj.Inverse(); + + Vec3f nearPosProj = inversePickMVPGuess.Transform(Vec3f(pickXCanonical, pickYCanonical, -1), 1); + + Vec3f farPosProj = inversePickMVPGuess.Transform(Vec3f(pickXCanonical, pickYCanonical, 1), 1); + + rayDir = (farPosProj - nearPosProj); + rayDir.Normalise(); + + if(testDir.z < 0) + { + rayDir = -rayDir; + } + rayPos = nearPosProj; + } + else + { + rayDir = testDir; + rayPos = cameraToWorldNearPosition; + } + } + + cbuf.RayPos = rayPos; + cbuf.RayDir = rayDir; + + cbuf.PickMVP = cfg.position.unproject ? pickMVPProj : pickMVP; + + bool isTriangleMesh = true; + switch(cfg.position.topology) + { + case Topology::TriangleList: + { + cbuf.MeshMode = MESH_TRIANGLE_LIST; + break; + } + case Topology::TriangleStrip: + { + cbuf.MeshMode = MESH_TRIANGLE_STRIP; + break; + } + case Topology::TriangleList_Adj: + { + cbuf.MeshMode = MESH_TRIANGLE_LIST_ADJ; + break; + } + case Topology::TriangleStrip_Adj: + { + cbuf.MeshMode = MESH_TRIANGLE_STRIP_ADJ; + break; + } + default: // points, lines, patchlists, unknown + { + cbuf.MeshMode = MESH_OTHER; + isTriangleMesh = false; + } + } + + ID3D11Buffer *vb = NULL, *ib = NULL; + DXGI_FORMAT ifmt = cfg.position.indexByteStride == 4 ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; + + { + auto it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.vertexResourceId); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + vb = it->second.m_Buffer; + + it = WrappedID3D11Buffer::m_BufferList.find(cfg.position.indexResourceId); + + if(it != WrappedID3D11Buffer::m_BufferList.end()) + ib = it->second.m_Buffer; + } + + HRESULT hr = S_OK; + + // most IB/VBs will not be available as SRVs. So, we copy into our own buffers. + // In the case of VB we also tightly pack and unpack the data. IB can just be + // read as R16 or R32 via the SRV so it is just a straight copy + + if(cfg.position.indexByteStride) + { + // resize up on demand + if(m_DebugRender.PickIBBuf == NULL || + m_DebugRender.PickIBSize < cfg.position.numIndices * cfg.position.indexByteStride) + { + SAFE_RELEASE(m_DebugRender.PickIBBuf); + SAFE_RELEASE(m_DebugRender.PickIBSRV); + + D3D11_BUFFER_DESC desc = {cfg.position.numIndices * cfg.position.indexByteStride, + D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, + 0, + 0, + 0}; + + m_DebugRender.PickIBSize = cfg.position.numIndices * cfg.position.indexByteStride; + + hr = m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.PickIBBuf); + + if(FAILED(hr)) + { + RDCERR("Failed to create PickIBBuf HRESULT: %s", ToStr(hr).c_str()); + return ~0U; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; + sdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + sdesc.Format = ifmt; + sdesc.Buffer.FirstElement = 0; + sdesc.Buffer.NumElements = cfg.position.numIndices; + + hr = m_pDevice->CreateShaderResourceView(m_DebugRender.PickIBBuf, &sdesc, + &m_DebugRender.PickIBSRV); + + if(FAILED(hr)) + { + SAFE_RELEASE(m_DebugRender.PickIBBuf); + RDCERR("Failed to create PickIBSRV HRESULT: %s", ToStr(hr).c_str()); + return ~0U; + } + } + + // copy index data as-is, the view format will take care of the rest + + RDCASSERT(cfg.position.indexByteOffset < 0xffffffff); + + if(ib) + { + D3D11_BUFFER_DESC ibdesc; + ib->GetDesc(&ibdesc); + + D3D11_BOX box; + box.front = 0; + box.back = 1; + box.left = (uint32_t)cfg.position.indexByteOffset; + box.right = (uint32_t)cfg.position.indexByteOffset + + cfg.position.numIndices * cfg.position.indexByteStride; + box.top = 0; + box.bottom = 1; + + box.right = RDCMIN(box.right, ibdesc.ByteWidth - (uint32_t)cfg.position.indexByteOffset); + + m_pImmediateContext->CopySubresourceRegion(m_DebugRender.PickIBBuf, 0, 0, 0, 0, ib, 0, &box); + } + } + + if(m_DebugRender.PickVBBuf == NULL || + m_DebugRender.PickVBSize < cfg.position.numIndices * sizeof(Vec4f)) + { + SAFE_RELEASE(m_DebugRender.PickVBBuf); + SAFE_RELEASE(m_DebugRender.PickVBSRV); + + D3D11_BUFFER_DESC desc = {cfg.position.numIndices * sizeof(Vec4f), + D3D11_USAGE_DEFAULT, + D3D11_BIND_SHADER_RESOURCE, + 0, + 0, + 0}; + + m_DebugRender.PickVBSize = cfg.position.numIndices * sizeof(Vec4f); + + hr = m_pDevice->CreateBuffer(&desc, NULL, &m_DebugRender.PickVBBuf); + + if(FAILED(hr)) + { + RDCERR("Failed to create PickVBBuf HRESULT: %s", ToStr(hr).c_str()); + return ~0U; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; + sdesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + sdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + sdesc.Buffer.FirstElement = 0; + sdesc.Buffer.NumElements = cfg.position.numIndices; + + hr = m_pDevice->CreateShaderResourceView(m_DebugRender.PickVBBuf, &sdesc, + &m_DebugRender.PickVBSRV); + + if(FAILED(hr)) + { + SAFE_RELEASE(m_DebugRender.PickVBBuf); + RDCERR("Failed to create PickVBSRV HRESULT: %s", ToStr(hr).c_str()); + return ~0U; + } + } + + // unpack and linearise the data + if(vb) + { + FloatVector *vbData = new FloatVector[cfg.position.numIndices]; + + bytebuf oldData; + GetBufferData(vb, cfg.position.vertexByteOffset, 0, oldData); + + byte *data = &oldData[0]; + byte *dataEnd = data + oldData.size(); + + bool valid; + + uint32_t idxclamp = 0; + if(cfg.position.baseVertex < 0) + idxclamp = uint32_t(-cfg.position.baseVertex); + + for(uint32_t i = 0; i < cfg.position.numIndices; i++) + { + uint32_t idx = i; + + // apply baseVertex but clamp to 0 (don't allow index to become negative) + if(idx < idxclamp) + idx = 0; + else if(cfg.position.baseVertex < 0) + idx -= idxclamp; + else if(cfg.position.baseVertex > 0) + idx += cfg.position.baseVertex; + + vbData[i] = HighlightCache::InterpretVertex(data, idx, cfg, dataEnd, valid); + } + + D3D11_BOX box; + box.top = 0; + box.bottom = 1; + box.front = 0; + box.back = 1; + box.left = 0; + box.right = cfg.position.numIndices * sizeof(Vec4f); + + m_pImmediateContext->UpdateSubresource(m_DebugRender.PickVBBuf, 0, &box, vbData, sizeof(Vec4f), + sizeof(Vec4f)); + + delete[] vbData; + } + + ID3D11ShaderResourceView *srvs[2] = {m_DebugRender.PickIBSRV, m_DebugRender.PickVBSRV}; + + ID3D11Buffer *buf = MakeCBuffer(&cbuf, sizeof(cbuf)); + + m_pImmediateContext->CSSetConstantBuffers(0, 1, &buf); + + m_pImmediateContext->CSSetShaderResources(0, 2, srvs); + + UINT reset = 0; + m_pImmediateContext->CSSetUnorderedAccessViews(0, 1, &m_DebugRender.PickResultUAV, &reset); + + m_pImmediateContext->CSSetShader(m_DebugRender.MeshPickCS, NULL, 0); + + m_pImmediateContext->Dispatch(cfg.position.numIndices / 1024 + 1, 1, 1); + + m_pImmediateContext->CopyStructureCount(m_DebugRender.histogramBuff, 0, + m_DebugRender.PickResultUAV); + + bytebuf results; + GetBufferData(m_DebugRender.histogramBuff, 0, 0, results); + + uint32_t numResults = *(uint32_t *)&results[0]; + + if(numResults > 0) + { + if(isTriangleMesh) + { + struct PickResult + { + uint32_t vertid; + Vec3f intersectionPoint; + }; + + GetBufferData(m_DebugRender.PickResultBuf, 0, 0, results); + + PickResult *pickResults = (PickResult *)&results[0]; + + PickResult *closest = pickResults; + + // distance from raycast hit to nearest worldspace position of the mouse + float closestPickDistance = (closest->intersectionPoint - rayPos).Length(); + + // min with size of results buffer to protect against overflows + for(uint32_t i = 1; i < RDCMIN((uint32_t)DebugRenderData::maxMeshPicks, numResults); i++) + { + float pickDistance = (pickResults[i].intersectionPoint - rayPos).Length(); + if(pickDistance < closestPickDistance) + { + closest = pickResults + i; + } + } + + return closest->vertid; + } + else + { + struct PickResult + { + uint32_t vertid; + uint32_t idx; + float len; + float depth; + }; + + GetBufferData(m_DebugRender.PickResultBuf, 0, 0, results); + + PickResult *pickResults = (PickResult *)&results[0]; + + PickResult *closest = pickResults; + + // min with size of results buffer to protect against overflows + for(uint32_t i = 1; i < RDCMIN((uint32_t)DebugRenderData::maxMeshPicks, numResults); i++) + { + // We need to keep the picking order consistent in the face + // of random buffer appends, when multiple vertices have the + // identical position (e.g. if UVs or normals are different). + // + // We could do something to try and disambiguate, but it's + // never going to be intuitive, it's just going to flicker + // confusingly. + if(pickResults[i].len < closest->len || + (pickResults[i].len == closest->len && pickResults[i].depth < closest->depth) || + (pickResults[i].len == closest->len && pickResults[i].depth == closest->depth && + pickResults[i].vertid < closest->vertid)) + closest = pickResults + i; + } + + return closest->vertid; + } + } + + return ~0U; +} + +void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, + uint32_t mip, uint32_t sample, CompType typeHint, float pixel[4]) +{ + D3D11RenderStateTracker tracker(m_WrappedContext); + + D3D11MarkerRegion marker("PickPixel"); + + m_pImmediateContext->OMSetRenderTargets(1, &m_DebugRender.PickPixelRT, NULL); + + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + m_pImmediateContext->ClearRenderTargetView(m_DebugRender.PickPixelRT, color); + + D3D11_VIEWPORT viewport; + RDCEraseEl(viewport); + + int oldW = GetWidth(), oldH = GetHeight(); + + SetOutputDimensions(100, 100); + + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = 100; + viewport.Height = 100; + + m_pImmediateContext->RSSetViewports(1, &viewport); + + { + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = true; + texDisplay.flipY = false; + texDisplay.mip = mip; + texDisplay.sampleIdx = sample; + texDisplay.customShaderId = ResourceId(); + texDisplay.sliceFace = sliceFace; + texDisplay.rangeMin = 0.0f; + texDisplay.rangeMax = 1.0f; + texDisplay.scale = 1.0f; + texDisplay.resourceId = texture; + texDisplay.typeHint = typeHint; + texDisplay.rawOutput = true; + texDisplay.xOffset = -float(x); + texDisplay.yOffset = -float(y); + + RenderTexture(texDisplay, false); + } + + D3D11_BOX box; + box.front = 0; + box.back = 1; + box.left = 0; + box.right = 1; + box.top = 0; + box.bottom = 1; + + ID3D11Resource *res = NULL; + m_DebugRender.PickPixelRT->GetResource(&res); + + m_pImmediateContext->CopySubresourceRegion(m_DebugRender.PickPixelStageTex, 0, 0, 0, 0, res, 0, + &box); + + SAFE_RELEASE(res); + + D3D11_MAPPED_SUBRESOURCE mapped; + mapped.pData = NULL; + HRESULT hr = + m_pImmediateContext->Map(m_DebugRender.PickPixelStageTex, 0, D3D11_MAP_READ, 0, &mapped); + + if(FAILED(hr)) + { + RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); + } + + float *pix = (float *)mapped.pData; + + if(pix == NULL) + { + RDCERR("Failed to map pick-pixel staging texture."); + } + else + { + pixel[0] = pix[0]; + pixel[1] = pix[1]; + pixel[2] = pix[2]; + pixel[3] = pix[3]; + } + + SetOutputDimensions(oldW, oldH); + + m_pImmediateContext->Unmap(m_DebugRender.PickPixelStageTex, 0); +} + +void D3D11DebugManager::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip, + const GetTextureDataParams ¶ms, bytebuf &data) +{ + D3D11RenderStateTracker tracker(m_WrappedContext); + + ID3D11Resource *dummyTex = NULL; + + uint32_t subresource = 0; + uint32_t mips = 0; + + size_t bytesize = 0; + + if(WrappedID3D11Texture1D::m_TextureList.find(tex) != WrappedID3D11Texture1D::m_TextureList.end()) + { + WrappedID3D11Texture1D *wrapTex = + (WrappedID3D11Texture1D *)WrappedID3D11Texture1D::m_TextureList[tex].m_Texture; + + D3D11_TEXTURE1D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + ID3D11Texture1D *d = NULL; + + mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, 1, 1); + + if(mip >= mips || arrayIdx >= desc.ArraySize) + return; + + if(params.remap != RemapTexture::NoRemap) + { + RDCASSERT(params.remap == RemapTexture::RGBA8); + + desc.Format = + IsSRGBFormat(desc.Format) ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; + desc.ArraySize = 1; + } + + subresource = arrayIdx * mips + mip; + + HRESULT hr = m_pDevice->CreateTexture1D(&desc, NULL, &d); + + dummyTex = d; + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); + return; + } + + bytesize = GetByteSize(desc.Width, 1, 1, desc.Format, mip); + + if(params.remap != RemapTexture::NoRemap) + { + RDCASSERT(params.remap == RemapTexture::RGBA8); + + subresource = mip; + + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_RENDER_TARGET; + + ID3D11Texture1D *rtTex = NULL; + + hr = m_pDevice->CreateTexture1D(&desc, NULL, &rtTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create target texture to downcast texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + return; + } + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE1D; + rtvDesc.Format = desc.Format; + rtvDesc.Texture1D.MipSlice = mip; + + ID3D11RenderTargetView *wrappedrtv = NULL; + hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); + if(FAILED(hr)) + { + RDCERR("Couldn't create target rtv to downcast texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + SAFE_RELEASE(rtTex); + return; + } + + ID3D11RenderTargetView *rtv = wrappedrtv; + + m_pImmediateContext->OMSetRenderTargets(1, &rtv, NULL); + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(rtv, color); + + D3D11_VIEWPORT viewport = {0, 0, (float)(desc.Width >> mip), 1.0f, 0.0f, 1.0f}; + + int oldW = GetWidth(), oldH = GetHeight(); + SetOutputDimensions(desc.Width, 1); + m_pImmediateContext->RSSetViewports(1, &viewport); + + { + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = false; + texDisplay.overlay = DebugOverlay::NoOverlay; + texDisplay.flipY = false; + texDisplay.mip = mip; + texDisplay.sampleIdx = 0; + texDisplay.customShaderId = ResourceId(); + texDisplay.sliceFace = arrayIdx; + texDisplay.rangeMin = params.blackPoint; + texDisplay.rangeMax = params.whitePoint; + texDisplay.scale = 1.0f; + texDisplay.resourceId = tex; + texDisplay.typeHint = params.typeHint; + texDisplay.rawOutput = false; + texDisplay.xOffset = 0; + texDisplay.yOffset = 0; + + RenderTexture(texDisplay, false); + } + + SetOutputDimensions(oldW, oldH); + + m_pImmediateContext->CopyResource(d, rtTex); + SAFE_RELEASE(rtTex); + + SAFE_RELEASE(wrappedrtv); + } + else + { + m_pImmediateContext->CopyResource(d, wrapTex); + } + } + else if(WrappedID3D11Texture2D1::m_TextureList.find(tex) != + WrappedID3D11Texture2D1::m_TextureList.end()) + { + WrappedID3D11Texture2D1 *wrapTex = + (WrappedID3D11Texture2D1 *)WrappedID3D11Texture2D1::m_TextureList[tex].m_Texture; + + D3D11_TEXTURE2D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + bool wasms = false; + + if(desc.SampleDesc.Count > 1) + { + desc.ArraySize *= desc.SampleDesc.Count; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + wasms = true; + } + + ID3D11Texture2D *d = NULL; + + mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, 1); + + if(mip >= mips || arrayIdx >= desc.ArraySize) + return; + + if(params.remap != RemapTexture::NoRemap) + { + RDCASSERT(params.remap == RemapTexture::RGBA8); + + desc.Format = (IsSRGBFormat(desc.Format) || wrapTex->m_RealDescriptor) + ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB + : DXGI_FORMAT_R8G8B8A8_UNORM; + desc.ArraySize = 1; + } + + subresource = arrayIdx * mips + mip; + + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &d); + + dummyTex = d; + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); + return; + } + + bytesize = GetByteSize(desc.Width, desc.Height, 1, desc.Format, mip); + + if(params.remap != RemapTexture::NoRemap) + { + RDCASSERT(params.remap == RemapTexture::RGBA8); + + subresource = mip; + + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_RENDER_TARGET; + + ID3D11Texture2D *rtTex = NULL; + + hr = m_pDevice->CreateTexture2D(&desc, NULL, &rtTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create target texture to downcast texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + return; + } + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Format = desc.Format; + rtvDesc.Texture2D.MipSlice = mip; + + ID3D11RenderTargetView *wrappedrtv = NULL; + hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); + if(FAILED(hr)) + { + RDCERR("Couldn't create target rtv to downcast texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + SAFE_RELEASE(rtTex); + return; + } + + ID3D11RenderTargetView *rtv = wrappedrtv; + + m_pImmediateContext->OMSetRenderTargets(1, &rtv, NULL); + float color[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(rtv, color); + + D3D11_VIEWPORT viewport = {0, 0, (float)(desc.Width >> mip), (float)(desc.Height >> mip), + 0.0f, 1.0f}; + + int oldW = GetWidth(), oldH = GetHeight(); + SetOutputDimensions(desc.Width, desc.Height); + m_pImmediateContext->RSSetViewports(1, &viewport); + + { + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = false; + texDisplay.overlay = DebugOverlay::NoOverlay; + texDisplay.flipY = false; + texDisplay.mip = mip; + texDisplay.sampleIdx = params.resolve ? ~0U : arrayIdx; + texDisplay.customShaderId = ResourceId(); + texDisplay.sliceFace = arrayIdx; + texDisplay.rangeMin = params.blackPoint; + texDisplay.rangeMax = params.whitePoint; + texDisplay.scale = 1.0f; + texDisplay.resourceId = tex; + texDisplay.typeHint = params.typeHint; + texDisplay.rawOutput = false; + texDisplay.xOffset = 0; + texDisplay.yOffset = 0; + + RenderTexture(texDisplay, false); + } + + SetOutputDimensions(oldW, oldH); + + m_pImmediateContext->CopyResource(d, rtTex); + SAFE_RELEASE(rtTex); + + SAFE_RELEASE(wrappedrtv); + } + else if(wasms && params.resolve) + { + desc.Usage = D3D11_USAGE_DEFAULT; + desc.CPUAccessFlags = 0; + + ID3D11Texture2D *resolveTex = NULL; + + hr = m_pDevice->CreateTexture2D(&desc, NULL, &resolveTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create target texture to resolve texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + return; + } + + m_pImmediateContext->ResolveSubresource(resolveTex, arrayIdx, wrapTex, arrayIdx, desc.Format); + m_pImmediateContext->CopyResource(d, resolveTex); + + SAFE_RELEASE(resolveTex); + } + else if(wasms) + { + CopyTex2DMSToArray(UNWRAP(WrappedID3D11Texture2D1, d), wrapTex->GetReal()); + } + else + { + m_pImmediateContext->CopyResource(d, wrapTex); + } + } + else if(WrappedID3D11Texture3D1::m_TextureList.find(tex) != + WrappedID3D11Texture3D1::m_TextureList.end()) + { + WrappedID3D11Texture3D1 *wrapTex = + (WrappedID3D11Texture3D1 *)WrappedID3D11Texture3D1::m_TextureList[tex].m_Texture; + + D3D11_TEXTURE3D_DESC desc = {0}; + wrapTex->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.MiscFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + + ID3D11Texture3D *d = NULL; + + mips = desc.MipLevels ? desc.MipLevels : CalcNumMips(desc.Width, desc.Height, desc.Depth); + + if(mip >= mips) + return; + + if(params.remap != RemapTexture::NoRemap) + { + RDCASSERT(params.remap == RemapTexture::RGBA8); + + desc.Format = + IsSRGBFormat(desc.Format) ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB : DXGI_FORMAT_R8G8B8A8_UNORM; + } + + subresource = mip; + + HRESULT hr = m_pDevice->CreateTexture3D(&desc, NULL, &d); + + dummyTex = d; + + if(FAILED(hr)) + { + RDCERR("Couldn't create staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); + return; + } + + bytesize = GetByteSize(desc.Width, desc.Height, desc.Depth, desc.Format, mip); + + if(params.remap != RemapTexture::NoRemap) + { + RDCASSERT(params.remap == RemapTexture::RGBA8); + + subresource = mip; + + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_RENDER_TARGET; + + ID3D11Texture3D *rtTex = NULL; + + hr = m_pDevice->CreateTexture3D(&desc, NULL, &rtTex); + + if(FAILED(hr)) + { + RDCERR("Couldn't create target texture to downcast texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + return; + } + + D3D11_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D; + rtvDesc.Format = desc.Format; + rtvDesc.Texture3D.MipSlice = mip; + rtvDesc.Texture3D.FirstWSlice = 0; + rtvDesc.Texture3D.WSize = 1; + ID3D11RenderTargetView *wrappedrtv = NULL; + ID3D11RenderTargetView *rtv = NULL; + + D3D11_VIEWPORT viewport = {0, 0, (float)(desc.Width >> mip), (float)(desc.Height >> mip), + 0.0f, 1.0f}; + + int oldW = GetWidth(), oldH = GetHeight(); + + for(UINT i = 0; i < (desc.Depth >> mip); i++) + { + rtvDesc.Texture3D.FirstWSlice = i; + hr = m_pDevice->CreateRenderTargetView(rtTex, &rtvDesc, &wrappedrtv); + if(FAILED(hr)) + { + RDCERR("Couldn't create target rtv to downcast texture. HRESULT: %s", ToStr(hr).c_str()); + SAFE_RELEASE(d); + SAFE_RELEASE(rtTex); + return; + } + + rtv = wrappedrtv; + + m_pImmediateContext->OMSetRenderTargets(1, &rtv, NULL); + float color[4] = {0.0f, 0.5f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(rtv, color); + + SetOutputDimensions(desc.Width, desc.Height); + m_pImmediateContext->RSSetViewports(1, &viewport); + + TextureDisplay texDisplay; + + texDisplay.red = texDisplay.green = texDisplay.blue = texDisplay.alpha = true; + texDisplay.hdrMultiplier = -1.0f; + texDisplay.linearDisplayAsGamma = false; + texDisplay.overlay = DebugOverlay::NoOverlay; + texDisplay.flipY = false; + texDisplay.mip = mip; + texDisplay.sampleIdx = 0; + texDisplay.customShaderId = ResourceId(); + texDisplay.sliceFace = i << mip; + texDisplay.rangeMin = params.blackPoint; + texDisplay.rangeMax = params.whitePoint; + texDisplay.scale = 1.0f; + texDisplay.resourceId = tex; + texDisplay.typeHint = params.typeHint; + texDisplay.rawOutput = false; + texDisplay.xOffset = 0; + texDisplay.yOffset = 0; + + RenderTexture(texDisplay, false); + + SAFE_RELEASE(wrappedrtv); + } + + SetOutputDimensions(oldW, oldH); + + m_pImmediateContext->CopyResource(d, rtTex); + SAFE_RELEASE(rtTex); + } + else + { + m_pImmediateContext->CopyResource(d, wrapTex); + } + } + else + { + RDCERR("Trying to get texture data for unknown ID %llu!", tex); + return; + } + + MapIntercept intercept; + + D3D11_MAPPED_SUBRESOURCE mapped = {0}; + HRESULT hr = m_pImmediateContext->Map(dummyTex, subresource, D3D11_MAP_READ, 0, &mapped); + + if(SUCCEEDED(hr)) + { + data.resize(bytesize); + intercept.InitWrappedResource(dummyTex, subresource, data.data()); + intercept.SetD3D(mapped); + intercept.CopyFromD3D(); + + // for 3D textures if we wanted a particular slice (arrayIdx > 0) + // copy it into the beginning. + if(intercept.numSlices > 1 && arrayIdx > 0 && (int)arrayIdx < intercept.numSlices) + { + byte *dst = data.data(); + byte *src = data.data() + intercept.app.DepthPitch * arrayIdx; + + for(int row = 0; row < intercept.numRows; row++) + { + memcpy(dst, src, intercept.app.RowPitch); + + src += intercept.app.RowPitch; + dst += intercept.app.RowPitch; + } + } + } + else + { + RDCERR("Couldn't map staging texture to retrieve data. HRESULT: %s", ToStr(hr).c_str()); + } + + SAFE_RELEASE(dummyTex); +} + +ResourceId D3D11DebugManager::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip, + uint32_t arrayIdx, uint32_t sampleIdx, + CompType typeHint) +{ + TextureShaderDetails details = GetShaderDetails(texid, typeHint, false); + + CreateCustomShaderTex(details.texWidth, details.texHeight); + + D3D11RenderStateTracker tracker(m_WrappedContext); + + { + D3D11_RENDER_TARGET_VIEW_DESC desc; + + desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + desc.Texture2D.MipSlice = mip; + + WrappedID3D11Texture2D1 *wrapped = (WrappedID3D11Texture2D1 *)m_CustomShaderTex; + HRESULT hr = m_pDevice->CreateRenderTargetView(wrapped, &desc, &m_CustomShaderRTV); + + if(FAILED(hr)) + { + RDCERR("Failed to create custom shader rtv HRESULT: %s", ToStr(hr).c_str()); + return m_CustomShaderResourceId; + } + } + + m_pImmediateContext->OMSetRenderTargets(1, &m_CustomShaderRTV, NULL); + + float clr[] = {0.0f, 0.0f, 0.0f, 0.0f}; + m_pImmediateContext->ClearRenderTargetView(m_CustomShaderRTV, clr); + + D3D11_VIEWPORT viewport; + RDCEraseEl(viewport); + + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = (float)RDCMAX(1U, details.texWidth >> mip); + viewport.Height = (float)RDCMAX(1U, details.texHeight >> mip); + + m_pImmediateContext->RSSetViewports(1, &viewport); + + TextureDisplay disp; + disp.red = disp.green = disp.blue = disp.alpha = true; + disp.flipY = false; + disp.xOffset = 0.0f; + disp.yOffset = 0.0f; + disp.customShaderId = shader; + disp.resourceId = texid; + disp.typeHint = typeHint; + disp.backgroundColor = FloatVector(0, 0, 0, 1.0); + disp.hdrMultiplier = -1.0f; + disp.linearDisplayAsGamma = false; + disp.mip = mip; + disp.sampleIdx = sampleIdx; + disp.overlay = DebugOverlay::NoOverlay; + disp.rangeMin = 0.0f; + disp.rangeMax = 1.0f; + disp.rawOutput = false; + disp.scale = 1.0f; + disp.sliceFace = arrayIdx; + + SetOutputDimensions(RDCMAX(1U, details.texWidth >> mip), RDCMAX(1U, details.texHeight >> mip)); + + RenderTexture(disp, true); + + return m_CustomShaderResourceId; +} + +void D3D11DebugManager::CreateCustomShaderTex(uint32_t w, uint32_t h) +{ + D3D11_TEXTURE2D_DESC texdesc; + + texdesc.ArraySize = 1; + texdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + texdesc.CPUAccessFlags = 0; + texdesc.MipLevels = CalcNumMips((int)w, (int)h, 1); + texdesc.MiscFlags = 0; + texdesc.SampleDesc.Count = 1; + texdesc.SampleDesc.Quality = 0; + texdesc.Usage = D3D11_USAGE_DEFAULT; + texdesc.Width = w; + texdesc.Height = h; + texdesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + + if(m_CustomShaderTex) + { + D3D11_TEXTURE2D_DESC customTexDesc; + m_CustomShaderTex->GetDesc(&customTexDesc); + + if(customTexDesc.Width == w && customTexDesc.Height == h) + return; + + SAFE_RELEASE(m_CustomShaderRTV); + SAFE_RELEASE(m_CustomShaderTex); + } + + HRESULT hr = m_pDevice->CreateTexture2D(&texdesc, NULL, &m_CustomShaderTex); + + if(FAILED(hr)) + { + RDCERR("Failed to create custom shader tex HRESULT: %s", ToStr(hr).c_str()); + } + else + { + m_CustomShaderResourceId = GetIDForResource(m_CustomShaderTex); + } +} diff --git a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj index 03bad1148..e1f09dc8c 100644 --- a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj +++ b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj @@ -98,7 +98,6 @@ - diff --git a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters index a1d20137f..bb6120744 100644 --- a/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters +++ b/renderdoc/driver/d3d11/renderdoc_d3d11.vcxproj.filters @@ -48,9 +48,6 @@ Replay - - Replay - Util