diff --git a/.travis.yml b/.travis.yml index 980b46cf29..fccac6dc0b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: cpp +sudo: required +dist: trusty branches: only: @@ -28,31 +30,21 @@ matrix: include: # only build docs on linux - os: linux - dist: trusty - sudo: false env: DOCS_BUILD=1 - os: linux - dist: trusty - sudo: required env: LINUX_BUILD=1 compiler: gcc - os: linux - dist: trusty - sudo: required env: LINUX_BUILD=1 compiler: clang - os: linux - dist: trusty - sudo: required env: LINUX_BUILD=1 RELEASE_BUILD=1 compiler: clang - os: linux - dist: trusty - sudo: required env: ANDROID_BUILD=1 compiler: clang - os: osx - osx_image: xcode8.2 + osx_image: xcode9.1 env: APPLE_BUILD=1 compiler: clang diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f412a4ded2..d9accbf604 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,7 @@ +# Soft-locked branch + +This branch (v0.x) is soft-locked. Active development is continuing on the v1.x branch, and v0.x will only get cherry-picked fixes. Please open all PRs against v1.x, and changes will be manually moved across to v0.x as and when needed. + # Contributing to RenderDoc ---- @@ -40,6 +44,20 @@ Configuration is available for cmake, [documented elsewhere](https://cmake.org/d Mac support is pretty early and while it will compile, it's not usable for debugging yet. Builds happen with cmake the same way as Linux. +### Android + +To build the components required to debug an Android target, first gather everything from [Dependencies](#dependencies) below, then run: +``` +mkdir build-android +cd build-android +cmake -DBUILD_ANDROID=On -DANDROID_ABI=armeabi-v7a -DANDROID_NATIVE_API_LEVEL=23 .. +make +``` +On Windows, you need to specify the 'generator' type to the cmake invocation. The exact parameter will depend on your bash shell, but options are e.g. -G "MSYS Makefiles" or -G "MinGW Makefiles", i.e.: +``` +cmake -DBUILD_ANDROID=On -DANDROID_ABI=armeabi-v7a -DANDROID_NATIVE_API_LEVEL=23 -G"MSYS Makefiles" .. +``` + # Code of Conduct I want to ensure that anyone can contribute to RenderDoc with only the next bug to worry about. For that reason the project has adopted the [contributor covenent](CODE_OF_CONDUCT.md) as a code of conduct to be enforced for anyone taking part in RenderDoc development. If you have any queries in this regard you can get in touch with me [directly over email](mailto:baldurk@baldurk.org). @@ -149,6 +167,91 @@ brew install cmake qt5 brew link qt5 --force ``` +### Android + +To build for Android, you must download components of the Android SDK, the Android NDK, and Java Development Kit. + +If you've already got the tools required, simply set the following three environment variables: +``` +export ANDROID_SDK= +export ANDROID_NDK= +export JAVA_HOME= +``` +Otherwise, below are steps to acquire the tools for each platform. +#### Ubuntu +The Java Development Kit can be installed with: +``` +sudo apt-get install openjdk-8-jdk +export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 +``` + +The Android SDK and NDK can be set up with the following steps. They are also mirrored in our Travis-CI [setup script](scripts/travis/android_setup.sh) for Android. We are currently targeting build-tools 26.0.1 and NDK r14b. + +SDK links are pulled from [here](https://developer.android.com/studio/index.html). + +NDK links are pulled from [here](https://developer.android.com/ndk/downloads/older_releases.html). +``` +# Set up Android SDK +export ANDROID_SDK= +pushd $ANDROID_SDK +wget http://dl.google.com/android/repository/sdk-tools-linux-3859397.zip +unzip sdk-tools-linux-3859397.zip +cd tools/bin/ +./sdkmanager --sdk_root=$ANDROID_SDK "build-tools;26.0.1" "platforms;android-23" +# Accept the license + +# Set up Android NDK +pushd $ANDROID_SDK +wget http://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip +unzip android-ndk-r14b-linux-x86_64.zip +export ANDROID_NDK=$ANDROID_SDK/android-ndk-r14b +``` +#### macOS +JDK can be installed with brew: +``` +brew cask install java +export JAVA_HOME="$(/usr/libexec/java_home)" +``` +Android NDK and SDK: +``` +# Set up Android SDK +export ANDROID_SDK= +pushd $ANDROID_SDK +wget https://dl.google.com/android/repository/sdk-tools-darwin-3859397.zip +unzip sdk-tools-darwin-3859397.zip +cd tools/bin/ +./sdkmanager --sdk_root=$ANDROID_SDK "build-tools;26.0.1" "platforms;android-23" +# Accept the license + +# Set up Android NDK +pushd $ANDROID_SDK +wget https://dl.google.com/android/repository/android-ndk-r14b-darwin-x86_64.zip +unzip android-ndk-r14b-darwin-x86_64.zip +export ANDROID_NDK=$ANDROID_SDK/android-ndk-r14b +``` +#### Windows +JDK can be installed from the following [link](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). +``` +set JAVA_HOME= +``` +Android NDK and SDK: +``` +# Set up the Android SDK +set ANDROID_SDK= +cd %ANDROID_SDK% +wget https://dl.google.com/android/repository/sdk-tools-windows-3859397.zip +unzip sdk-tools-windows-3859397.zip +cd tools\bin +sdkmanager --sdk_root=%ANDROID_SDK% "build-tools;26.0.1" "platforms;android-23" +# Accept the license + +# Set up the Android NDK +cd %ANDROID_SDK% +wget http://dl.google.com/android/repository/android-ndk-r14b-windows-x86_64.zip +unzip android-ndk-r14b-windows-x86_64.zip +set ANDROID_NDK=%ANDROID_SDK%\android-ndk-r14b +``` + # Where to Start There are always plenty of things to do, if you'd like to chip in! Check out the [Roadmap](https://github.com/baldurk/renderdoc/wiki/Roadmap) page in the wiki for future tasks to tackle, or have a look at the [issues](https://github.com/baldurk/renderdoc/issues) for outstanding bugs. I'll try and tag things that seem like small changes that would be a good way for someone to get started with. diff --git a/README.md b/README.md index 956ec02b07..530d226a09 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ RenderDoc [![Coverity Scan](https://scan.coverity.com/projects/8525/badge.svg)](https://scan.coverity.com/projects/baldurk-renderdoc) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md) -RenderDoc - a graphics debugger, currently available for Vulkan, D3D11, D3D12, and OpenGL development on windows. +RenderDoc - a graphics debugger, currently available for Vulkan, D3D11, D3D12, and OpenGL development on Windows 7 - 10 and Linux. If you have any questions, suggestions or problems or you can [create an issue](https://github.com/baldurk/renderdoc/issues/new) here on github, [email me directly](mailto:baldurk@baldurk.org) or [come into IRC](https://kiwiirc.com/client/irc.freenode.net/#renderdoc) to discuss it. @@ -16,6 +16,10 @@ If you have any questions, suggestions or problems or you can [create an issue]( * **Information for developing/contributing**: [CONTRIBUTING.md](CONTRIBUTING.md), [Compilation instructions](CONTRIBUTING.md#compiling), [Roadmap](https://github.com/baldurk/renderdoc/wiki/Roadmap) * **Code of Conduct**: [Contributor Covenant](CODE_OF_CONDUCT.md) +### v0.x branch + +You are currently viewing the default v0.x branch. This branch is not seeing feature development and only limited bugfix cherry-picking, while development completes on v1.0. You can switch to the v1.x branch to get a (potentially unstable) preview of the current v1.0 build, or choose a v1.x nightly build above. + Screenshots -------------- diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp index 2a1945903d..ef93a6e7bd 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp @@ -519,6 +519,8 @@ void PythonContext::executeString(const QString &filename, const QString &source // catch any output outputTick(); + PyEval_SetTrace(NULL, NULL); + Py_XDECREF(thisobj); Py_XDECREF(traceContext); } diff --git a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp index 43a5419787..01161e1796 100644 --- a/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp +++ b/qrenderdoc/Widgets/Extended/RDTreeWidget.cpp @@ -559,6 +559,7 @@ void RDTreeWidget::scrollToItem(RDTreeWidgetItem *node) void RDTreeWidget::clear() { m_root->clear(); + m_currentHoverIndex = QModelIndex(); } void RDTreeWidget::mouseMoveEvent(QMouseEvent *e) diff --git a/qrenderdoc/Windows/BufferViewer.cpp b/qrenderdoc/Windows/BufferViewer.cpp index e8fffee0b8..3310c16108 100644 --- a/qrenderdoc/Windows/BufferViewer.cpp +++ b/qrenderdoc/Windows/BufferViewer.cpp @@ -2698,6 +2698,7 @@ void BufferViewer::CalcColumnWidth(int maxNumRows) FormatElement(headerText, 0, 16, false, 1, false, 1, intFmt, false, false)); m_ModelVSIn->numRows = 2; + m_ModelVSIn->baseVertex = 0; if(m_ModelVSIn->indices) m_ModelVSIn->indices->deref(); @@ -3190,7 +3191,7 @@ void BufferViewer::on_solidShading_currentIndexChanged(int index) m_Config.wireframeDraw = true; } - m_Config.solidShadeMode = (SolidShade)index; + m_Config.solidShadeMode = (SolidShade)qMax(0, index); m_ModelVSIn->setSecondaryColumn(m_ModelVSIn->secondaryColumn(), m_Config.solidShadeMode == SolidShade::Secondary, diff --git a/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp b/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp index 6dcf3a5cc4..7ae37105d1 100644 --- a/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp +++ b/qrenderdoc/Windows/Dialogs/EnvironmentEditor.cpp @@ -149,7 +149,7 @@ void EnvironmentEditor::on_addUpdate_clicked() EnvironmentModification mod; mod.name = ui->name->text().toUtf8().data(); mod.value = ui->value->text().toUtf8().data(); - mod.sep = (EnvSep)ui->separator->currentIndex(); + mod.sep = (EnvSep)qMax(0, ui->separator->currentIndex()); if(ui->appendValue->isChecked()) mod.mod = EnvMod::Append; diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp index 817e89f703..7e41131b79 100644 --- a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp +++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp @@ -294,7 +294,7 @@ void SettingsDialog::on_EventBrowser_TimeUnit_currentIndexChanged(int index) if(m_Init) return; - m_Ctx.Config().EventBrowser_TimeUnit = (TimeUnit)ui->EventBrowser_TimeUnit->currentIndex(); + m_Ctx.Config().EventBrowser_TimeUnit = (TimeUnit)qMax(0, ui->EventBrowser_TimeUnit->currentIndex()); if(m_Ctx.HasEventBrowser()) m_Ctx.GetEventBrowser()->UpdateDurationColumn(); diff --git a/qrenderdoc/Windows/Dialogs/TextureSaveDialog.cpp b/qrenderdoc/Windows/Dialogs/TextureSaveDialog.cpp index f95265e831..08daedde48 100644 --- a/qrenderdoc/Windows/Dialogs/TextureSaveDialog.cpp +++ b/qrenderdoc/Windows/Dialogs/TextureSaveDialog.cpp @@ -77,11 +77,17 @@ TextureSaveDialog::TextureSaveDialog(const TextureDescription &t, const TextureS ui->mipSelect->addItem( QFormatStr("%1 - %2x%3").arg(i).arg(qMax(1U, tex.width >> i)).arg(qMax(1U, tex.height >> i))); + // reset as it might have been changed by adding items + saveData.mip = s.mip; + ui->mipSelect->setCurrentIndex(saveData.mip >= 0 ? saveData.mip : 0); for(uint32_t i = 0; i < tex.msSamp; i++) ui->sampleSelect->addItem(tr("Sample %1").arg(i)); + // reset as it might have been changed by adding items + saveData.sample = s.sample; + ui->sampleSelect->setCurrentIndex(qMin( (int)tex.msSamp, (saveData.sample.sampleIndex == ~0U ? 0 : (int)saveData.sample.sampleIndex))); @@ -114,6 +120,9 @@ TextureSaveDialog::TextureSaveDialog(const TextureDescription &t, const TextureS } } + // reset as it might have been changed by adding items + saveData.slice = s.slice; + ui->sliceSelect->setCurrentIndex(saveData.slice.sliceIndex >= 0 ? saveData.slice.sliceIndex : 0); ui->gridWidth->setMaximum(tex.depth * tex.arraysize * tex.msSamp); @@ -182,7 +191,7 @@ void TextureSaveDialog::SetFilenameFromFiletype() void TextureSaveDialog::on_fileFormat_currentIndexChanged(int index) { - saveData.destType = (FileType)ui->fileFormat->currentIndex(); + saveData.destType = (FileType)qMax(0, ui->fileFormat->currentIndex()); ui->jpegCompression->setEnabled(saveData.destType == FileType::JPG); @@ -264,7 +273,7 @@ void TextureSaveDialog::on_oneMip_toggled(bool checked) void TextureSaveDialog::on_mipSelect_currentIndexChanged(int index) { - saveData.mip = index; + saveData.mip = qMax(0, index); } void TextureSaveDialog::on_mapSampleArray_toggled(bool checked) @@ -335,7 +344,7 @@ void TextureSaveDialog::on_oneSample_toggled(bool checked) void TextureSaveDialog::on_sampleSelect_currentIndexChanged(int index) { - saveData.sample.sampleIndex = (uint32_t)index; + saveData.sample.sampleIndex = (uint32_t)qMax(0, index); } void TextureSaveDialog::on_exportAllSlices_toggled(bool checked) @@ -457,7 +466,7 @@ void TextureSaveDialog::on_cubeCruciform_toggled(bool checked) void TextureSaveDialog::on_sliceSelect_currentIndexChanged(int index) { - saveData.slice.sliceIndex = index; + saveData.slice.sliceIndex = qMax(0, index); } void TextureSaveDialog::on_gridWidth_valueChanged(double arg1) @@ -479,7 +488,7 @@ void TextureSaveDialog::on_alphaCol_clicked() void TextureSaveDialog::on_alphaMap_currentIndexChanged(int index) { - saveData.alpha = (AlphaMapping)index; + saveData.alpha = (AlphaMapping)qMax(0, index); ui->alphaCol->setEnabled(saveData.alpha == AlphaMapping::BlendToColor); } @@ -537,7 +546,7 @@ void TextureSaveDialog::on_filename_textEdited(const QString &arg1) void TextureSaveDialog::on_saveCancelButtons_accepted() { - saveData.alpha = (AlphaMapping)ui->alphaMap->currentIndex(); + saveData.alpha = (AlphaMapping)qMax(0, ui->alphaMap->currentIndex()); if(saveData.alpha == AlphaMapping::BlendToCheckerboard) { @@ -547,7 +556,7 @@ void TextureSaveDialog::on_saveCancelButtons_accepted() if(ui->exportAllMips->isChecked()) saveData.mip = -1; else - saveData.mip = (int)ui->mipSelect->currentIndex(); + saveData.mip = (int)qMax(0, ui->mipSelect->currentIndex()); if(ui->resolveSamples->isChecked()) { @@ -561,7 +570,7 @@ void TextureSaveDialog::on_saveCancelButtons_accepted() } else { - saveData.sample.sampleIndex = (uint)ui->sampleSelect->currentIndex(); + saveData.sample.sampleIndex = (uint)qMax(0, ui->sampleSelect->currentIndex()); saveData.sample.mapToArray = false; } @@ -569,7 +578,7 @@ void TextureSaveDialog::on_saveCancelButtons_accepted() { saveData.slice.cubeCruciform = saveData.slice.slicesAsGrid = false; saveData.slice.sliceGridWidth = 1; - saveData.slice.sliceIndex = (int)ui->sliceSelect->currentIndex(); + saveData.slice.sliceIndex = (int)qMax(0, ui->sliceSelect->currentIndex()); } else { @@ -588,7 +597,7 @@ void TextureSaveDialog::on_saveCancelButtons_accepted() } } - saveData.destType = (FileType)ui->fileFormat->currentIndex(); + saveData.destType = (FileType)qMax(0, ui->fileFormat->currentIndex()); saveData.jpegQuality = (int)ui->jpegCompression->value(); bool ok = false; diff --git a/qrenderdoc/Windows/EventBrowser.ui b/qrenderdoc/Windows/EventBrowser.ui index ad82120be8..42e64a3587 100644 --- a/qrenderdoc/Windows/EventBrowser.ui +++ b/qrenderdoc/Windows/EventBrowser.ui @@ -358,13 +358,14 @@ - + - :/arrow_right.png:/arrow_right.png + :/arrow_left.png:/arrow_left.png + true @@ -372,13 +373,13 @@ - + - :/arrow_left.png:/arrow_left.png + :/arrow_right.png:/arrow_right.png true diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index a7df0be841..61776734e0 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -1682,7 +1682,7 @@ void MainWindow::closeEvent(QCloseEvent *event) for(LiveCapture *live : m_LiveCaptures) { live->cleanItems(); - live->close(); + delete live; } SaveLayout(0); diff --git a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp index 8867a1bc1c..a04eff10a6 100644 --- a/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D11PipelineStateViewer.cpp @@ -1829,7 +1829,7 @@ void D3D11PipelineStateViewer::resource_itemActivated(RDTreeWidgetItem *item, in } else if(buf) { - D3D11ViewTag view; + D3D11ViewTag view = {}; if(tag.canConvert()) view = tag.value(); diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 4115bd537c..70af8ab122 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -672,6 +672,26 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(shaderDetails != NULL) { + // we find the matching binding for this set/binding. + // The spec requires that there are no overlapping definitions, or if there are they have + // compatible types so we can just pick the first one we come across. + // The spec also doesn't require variables which are statically unused to have valid bindings, + // so they may be overlapping or possibly just defaulted to 0. + // Any variables with no binding declared at all were set to 0 and sorted to the end at + // reflection time, so we can just use a single algorithm to select the best candidate: + // + // 1. Search for matching bindset/bind resources. It doesn't matter which 'namespace' (sampler/ + // read-only/read-write) we search in, because if there's a conflict the behaviour is + // illegal and if there's no conflict we won't get any ambiguity. + // 2. If we find a match, select it for use. + // 3. If we find a second match, use it in preference only if the old one was !used, and the new + // one is used. + // + // This will make us select the best possible option - the first declared used resource + // at a particular binding, ignoring any unused resources at that binding before/after. Or if + // there's no used resource at all, the first declared unused resource (which will prefer + // resources with proper bindings over those without, as with the sorting mentioned above). + for(int i = 0; i < shaderDetails->ReadOnlyResources.count; i++) { const ShaderResource &ro = shaderDetails->ReadOnlyResources[i]; @@ -679,9 +699,15 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset == bindset && stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind == bind) { - bindPoint = (uint)i; - shaderRes = &ro; - bindMap = &stage.BindpointMapping.ReadOnlyResources[ro.bindPoint]; + // use this one either if we have no candidate, or the candidate we have is unused and this + // one is used + if(bindMap == NULL || + (!bindMap->used && stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].used)) + { + bindPoint = (uint)i; + shaderRes = &ro; + bindMap = &stage.BindpointMapping.ReadOnlyResources[ro.bindPoint]; + } } } @@ -692,10 +718,16 @@ void VulkanPipelineStateViewer::addResourceRow(ShaderReflection *shaderDetails, if(stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset == bindset && stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind == bind) { - bindPoint = (uint)i; - isrw = true; - shaderRes = &rw; - bindMap = &stage.BindpointMapping.ReadWriteResources[rw.bindPoint]; + // use this one either if we have no candidate, or the candidate we have is unused and this + // one is used + if(bindMap == NULL || + (!bindMap->used && stage.BindpointMapping.ReadWriteResources[rw.bindPoint].used)) + { + bindPoint = (uint)i; + isrw = true; + shaderRes = &rw; + bindMap = &stage.BindpointMapping.ReadWriteResources[rw.bindPoint]; + } } } } @@ -1377,7 +1409,7 @@ void VulkanPipelineStateViewer::setShaderState(const VKPipe::Shader &stage, RDTreeWidgetItem *node = new RDTreeWidgetItem({QString(), QString(), ToQStr(cblock.name), tr("Push constants"), - QString(), tr("%1 Variable(s)", "", cblock.variables.count)}); + QString(), tr("%1 Variables").arg(cblock.variables.count)}); node->setTag(QVariant::fromValue(VulkanCBufferTag(cb, 0))); @@ -1704,6 +1736,8 @@ void VulkanPipelineStateViewer::setState() ui->sampleShading->setPixmap(state.MSAA.sampleShadingEnable ? tick : cross); ui->minSampleShading->setText(Formatter::Format(state.MSAA.minSampleShading)); ui->sampleMask->setText(Formatter::Format(state.MSAA.sampleMask, true)); + ui->alphaToOne->setPixmap(state.CB.alphaToOneEnable ? tick : cross); + ui->alphaToCoverage->setPixmap(state.CB.alphaToCoverageEnable ? tick : cross); //////////////////////////////////////////////// // Output Merger @@ -1880,7 +1914,6 @@ void VulkanPipelineStateViewer::setState() .arg(state.CB.blendConst[2], 0, 'f', 2) .arg(state.CB.blendConst[3], 0, 'f', 2)); ui->logicOp->setText(state.CB.logicOpEnable ? ToQStr(state.CB.logic) : lit("-")); - ui->alphaToOne->setPixmap(state.CB.alphaToOneEnable ? tick : cross); ui->depthEnabled->setPixmap(state.DS.depthTestEnable ? tick : cross); ui->depthFunc->setText(ToQStr(state.DS.depthCompareOp)); diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui index 79026fc29d..1f714a7f6e 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.ui @@ -2162,22 +2162,6 @@ - - - - Qt::Vertical - - - QSizePolicy::Preferred - - - - 0 - 0 - - - - @@ -2210,6 +2194,58 @@ + + + + Alpha to 1: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + :/cross.png + + + Qt::AlignCenter + + + 4 + + + + + + + Alpha to Coverage: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + true + + + + + + + :/cross.png + + + Qt::AlignCenter + + + 4 + + + @@ -2755,35 +2791,6 @@ - - - - Alpha to 1: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - true - - - - - - - - - - :/cross.png - - - Qt::AlignCenter - - - 4 - - - diff --git a/qrenderdoc/Windows/ShaderViewer.cpp b/qrenderdoc/Windows/ShaderViewer.cpp index 8629e58a26..d8c5e01323 100644 --- a/qrenderdoc/Windows/ShaderViewer.cpp +++ b/qrenderdoc/Windows/ShaderViewer.cpp @@ -515,8 +515,11 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR QString semIdx = s.needSemanticIndex ? QString::number(s.semanticIndex) : QString(); + QString regIdx = + s.systemValue == ShaderBuiltin::Undefined ? QString::number(s.regIndex) : lit("-"); + ui->inputSig->addTopLevelItem(new RDTreeWidgetItem( - {name, semIdx, s.regIndex, TypeString(s), ToQStr(s.systemValue), + {name, semIdx, QString::number(s.regIndex), TypeString(s), ToQStr(s.systemValue), GetComponentString(s.regChannelMask), GetComponentString(s.channelUsedMask)})); } @@ -543,8 +546,11 @@ void ShaderViewer::debugShader(const ShaderBindpointMapping *bind, const ShaderR QString semIdx = s.needSemanticIndex ? QString::number(s.semanticIndex) : QString(); + QString regIdx = + s.systemValue == ShaderBuiltin::Undefined ? QString::number(s.regIndex) : lit("-"); + ui->outputSig->addTopLevelItem(new RDTreeWidgetItem( - {name, semIdx, s.regIndex, TypeString(s), ToQStr(s.systemValue), + {name, semIdx, regIdx, TypeString(s), ToQStr(s.systemValue), GetComponentString(s.regChannelMask), GetComponentString(s.channelUsedMask)})); } } diff --git a/qrenderdoc/Windows/TextureViewer.cpp b/qrenderdoc/Windows/TextureViewer.cpp index 75374cf744..d40cac9d7a 100644 --- a/qrenderdoc/Windows/TextureViewer.cpp +++ b/qrenderdoc/Windows/TextureViewer.cpp @@ -1058,14 +1058,14 @@ void TextureViewer::UI_OnTextureSelectionChanged(bool newdraw) m_TextureSettings[m_TexDisplay.texid].b = ui->channelBlue->isChecked(); m_TextureSettings[m_TexDisplay.texid].a = ui->channelAlpha->isChecked(); - m_TextureSettings[m_TexDisplay.texid].displayType = ui->channels->currentIndex(); + m_TextureSettings[m_TexDisplay.texid].displayType = qMax(0, ui->channels->currentIndex()); m_TextureSettings[m_TexDisplay.texid].customShader = ui->customShader->currentText(); m_TextureSettings[m_TexDisplay.texid].depth = ui->depthDisplay->isChecked(); m_TextureSettings[m_TexDisplay.texid].stencil = ui->stencilDisplay->isChecked(); - m_TextureSettings[m_TexDisplay.texid].mip = ui->mipLevel->currentIndex(); - m_TextureSettings[m_TexDisplay.texid].slice = ui->sliceFace->currentIndex(); + m_TextureSettings[m_TexDisplay.texid].mip = qMax(0, ui->mipLevel->currentIndex()); + m_TextureSettings[m_TexDisplay.texid].slice = qMax(0, ui->sliceFace->currentIndex()); m_TextureSettings[m_TexDisplay.texid].minrange = ui->rangeHistogram->blackPoint(); m_TextureSettings[m_TexDisplay.texid].maxrange = ui->rangeHistogram->whitePoint(); @@ -3167,13 +3167,13 @@ void TextureViewer::on_mipLevel_currentIndexChanged(int index) if(tex.mips > 1) { - m_TexDisplay.mip = (uint32_t)index; + m_TexDisplay.mip = (uint32_t)qMax(0, index); m_TexDisplay.sampleIdx = 0; } else { m_TexDisplay.mip = 0; - m_TexDisplay.sampleIdx = (uint32_t)index; + m_TexDisplay.sampleIdx = (uint32_t)qMax(0, index); if(m_TexDisplay.sampleIdx == tex.msSamp) m_TexDisplay.sampleIdx = ~0U; } @@ -3188,7 +3188,7 @@ void TextureViewer::on_mipLevel_currentIndexChanged(int index) ui->sliceFace->clear(); for(uint32_t i = 0; i < numSlices; i++) - ui->sliceFace->addItem(tr("Slice ") + i); + ui->sliceFace->addItem(tr("Slice %1").arg(i)); // changing sliceFace index will handle updating range & re-picking ui->sliceFace->setCurrentIndex((int)qBound(0U, newSlice, numSlices - 1)); @@ -3213,10 +3213,10 @@ void TextureViewer::on_sliceFace_currentIndexChanged(int index) return; TextureDescription &tex = *texptr; - m_TexDisplay.sliceFace = (uint32_t)index; + m_TexDisplay.sliceFace = (uint32_t)qMax(0, index); if(tex.depth > 1) - m_TexDisplay.sliceFace = (uint32_t)(index << (int)m_TexDisplay.mip); + m_TexDisplay.sliceFace = (uint32_t)(qMax(0, index) << (int)m_TexDisplay.mip); INVOKE_MEMFN(RT_UpdateVisualRange); @@ -3343,6 +3343,7 @@ void TextureViewer::on_saveTex_clicked() TextureSave config; memset(&config, 0, sizeof(config)); + config.jpegQuality = 90; config.id = m_TexDisplay.texid; config.typeHint = m_TexDisplay.typeHint; diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index 6f997ab41b..c3a90fd47f 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -205,6 +205,9 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR APPLE) if(CMAKE_COMPILER_IS_GNUCXX) set_property(SOURCE 3rdparty/jpeg-compressor/jpgd.cpp APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unknown-warning -Wno-implicit-fallthrough") + + set_property(SOURCE serialise/utf8printf.cpp + APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-unknown-warning -Wno-format-truncation") endif() endif() diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index f94f3c724e..eaaacef6aa 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -118,7 +118,7 @@ struct XlibWindowData #else -typedef void *Display; +typedef struct _XDisplay Display; #endif diff --git a/renderdoc/api/replay/version.h b/renderdoc/api/replay/version.h index bd2a642088..5d602ab2eb 100644 --- a/renderdoc/api/replay/version.h +++ b/renderdoc/api/replay/version.h @@ -94,7 +94,7 @@ // upstream and should not be modified downstream. You can set DISTRIBUTION_VERSION to include any // arbitrary release marker or package version you wish. #define RENDERDOC_VERSION_MAJOR 0 -#define RENDERDOC_VERSION_MINOR 35 +#define RENDERDOC_VERSION_MINOR 91 #define RDOC_INTERNAL_VERSION_STRINGIZE2(a) #a #define RDOC_INTERNAL_VERSION_STRINGIZE(a) RDOC_INTERNAL_VERSION_STRINGIZE2(a) diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index c3977f93f1..4f362f91f3 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -162,11 +162,17 @@ void D3D11DebugManager::FillCBufferVariables(const string &prefix, size_t &offse 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: type = VarType::UInt; break; + case VARTYPE_UINT8: + case VARTYPE_MIN16UINT: type = VarType::UInt; break; case VARTYPE_DOUBLE: elemByteSize = 8; type = VarType::Double; @@ -833,6 +839,45 @@ void D3D11DebugManager::CreateShaderGlobalState(ShaderDebug::GlobalState &global sdesc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) global.srvs[i].format.byteWidth = 10; } + else + { + D3D11_RESOURCE_DIMENSION dim; + res->GetType(&dim); + + if(dim == D3D11_RESOURCE_DIMENSION_BUFFER) + { + ID3D11Buffer *buf = (ID3D11Buffer *)res; + D3D11_BUFFER_DESC bufdesc; + buf->GetDesc(&bufdesc); + + global.srvs[i].format.stride = bufdesc.StructureByteStride; + + // if we didn't get a type from the SRV description, try to pull it from the declaration + for(const DXBC::ShaderInputBind &bind : dxbc->m_Resources) + { + if(bind.reg == (uint32_t)i && bind.dimension == DXBC::ShaderInputBind::DIM_BUFFER && + bind.retType < DXBC::ShaderInputBind::RETTYPE_MIXED && + bind.retType != DXBC::ShaderInputBind::RETTYPE_UNKNOWN) + { + global.srvs[i].format.byteWidth = 4; + global.srvs[i].format.numComps = bind.numSamples; + + if(bind.retType == DXBC::ShaderInputBind::RETTYPE_UNORM) + global.srvs[i].format.fmt = CompType::UNorm; + else if(bind.retType == DXBC::ShaderInputBind::RETTYPE_SNORM) + global.srvs[i].format.fmt = CompType::SNorm; + else if(bind.retType == DXBC::ShaderInputBind::RETTYPE_UINT) + global.srvs[i].format.fmt = CompType::UInt; + else if(bind.retType == DXBC::ShaderInputBind::RETTYPE_SINT) + global.srvs[i].format.fmt = CompType::SInt; + else + global.srvs[i].format.fmt = CompType::Float; + + break; + } + } + } + } if(sdesc.ViewDimension == D3D11_SRV_DIMENSION_BUFFER) { @@ -1554,7 +1599,8 @@ ShaderDebugTrace D3D11DebugManager::DebugPixel(uint32_t eventID, uint32_t x, uin { const SigParameter &prev = dxbc->m_InputSig[i - 1]; - if(prev.compCount <= 2 && prev.regChannelMask <= 0x3) + if(prev.regIndex != dxbc->m_InputSig[i].regIndex && prev.compCount <= 2 && + prev.regChannelMask <= 0x3) arrayLength = 1; } @@ -5833,36 +5879,28 @@ vector D3D11DebugManager::PixelHistory(vector eve { WrappedID3D11RenderTargetView1 *rtv = (WrappedID3D11RenderTargetView1 *)view; - ResourceRange viewRange(rtv); - - if(viewRange.Intersects(resourceRange)) + if(rtv->GetResourceRange().Intersects(resourceRange)) used = true; } else if(WrappedID3D11DepthStencilView::IsAlloc(view)) { WrappedID3D11DepthStencilView *dsv = (WrappedID3D11DepthStencilView *)view; - ResourceRange viewRange(dsv); - - if(viewRange.Intersects(resourceRange)) + if(dsv->GetResourceRange().Intersects(resourceRange)) used = true; } else if(WrappedID3D11ShaderResourceView1::IsAlloc(view)) { WrappedID3D11ShaderResourceView1 *srv = (WrappedID3D11ShaderResourceView1 *)view; - ResourceRange viewRange(srv); - - if(viewRange.Intersects(resourceRange)) + if(srv->GetResourceRange().Intersects(resourceRange)) used = true; } else if(WrappedID3D11UnorderedAccessView1::IsAlloc(view)) { WrappedID3D11UnorderedAccessView1 *uav = (WrappedID3D11UnorderedAccessView1 *)view; - ResourceRange viewRange(uav); - - if(viewRange.Intersects(resourceRange)) + if(uav->GetResourceRange().Intersects(resourceRange)) used = true; } else diff --git a/renderdoc/driver/d3d11/d3d11_common.cpp b/renderdoc/driver/d3d11/d3d11_common.cpp index c23c27d4f9..246c6a87f4 100644 --- a/renderdoc/driver/d3d11/d3d11_common.cpp +++ b/renderdoc/driver/d3d11/d3d11_common.cpp @@ -75,7 +75,7 @@ void D3D11MarkerRegion::End() annot->EndEvent(); } -ResourceRange ResourceRange::Null = ResourceRange(NULL, 0, 0); +ResourceRange ResourceRange::Null = ResourceRange(ResourceRange::empty); ResourceRange::ResourceRange(ID3D11ShaderResourceView *srv) { @@ -92,6 +92,13 @@ ResourceRange::ResourceRange(ID3D11ShaderResourceView *srv) return; } +// in non-release make sure we always consistently check wrapped resources/views. Otherwise we could +// end up in a situation where we're comparing two resource ranges that do overlap, but one was +// constructed with the wrapped view and one wasn't - so they compare differently +#if ENABLED(RDOC_DEVEL) + RDCASSERT(WrappedID3D11ShaderResourceView1::IsAlloc(srv)); +#endif + ID3D11Resource *res = NULL; srv->GetResource(&res); res->Release(); @@ -214,6 +221,10 @@ ResourceRange::ResourceRange(ID3D11UnorderedAccessView *uav) return; } +#if ENABLED(RDOC_DEVEL) + RDCASSERT(WrappedID3D11UnorderedAccessView1::IsAlloc(uav)); +#endif + ID3D11Resource *res = NULL; uav->GetResource(&res); res->Release(); @@ -274,6 +285,10 @@ ResourceRange::ResourceRange(ID3D11RenderTargetView *rtv) return; } +#if ENABLED(RDOC_DEVEL) + RDCASSERT(WrappedID3D11RenderTargetView1::IsAlloc(rtv)); +#endif + ID3D11Resource *res = NULL; rtv->GetResource(&res); res->Release(); @@ -339,6 +354,10 @@ ResourceRange::ResourceRange(ID3D11DepthStencilView *dsv) return; } +#if ENABLED(RDOC_DEVEL) + RDCASSERT(WrappedID3D11DepthStencilView::IsAlloc(dsv)); +#endif + ID3D11Resource *res = NULL; dsv->GetResource(&res); res->Release(); @@ -387,6 +406,53 @@ ResourceRange::ResourceRange(ID3D11DepthStencilView *dsv) SetMaxes(numMips, numSlices); } +ResourceRange::ResourceRange(ID3D11Buffer *res) +{ +#if ENABLED(RDOC_DEVEL) + RDCASSERT(!res || WrappedID3D11Buffer::IsAlloc(res)); +#endif + + resource = res; + minMip = minSlice = 0; + maxMip = allMip; + maxSlice = allSlice; + fullRange = true; + depthReadOnly = false; + stencilReadOnly = false; +} + +ResourceRange::ResourceRange(ID3D11Texture2D *res) +{ +#if ENABLED(RDOC_DEVEL) + RDCASSERT(!res || WrappedID3D11Texture2D1::IsAlloc(res)); +#endif + + resource = res; + minMip = minSlice = 0; + maxMip = allMip; + maxSlice = allSlice; + fullRange = true; + depthReadOnly = false; + stencilReadOnly = false; +} + +ResourceRange::ResourceRange(ID3D11Resource *res, UINT mip, UINT slice) +{ +#if ENABLED(RDOC_DEVEL) + RDCASSERT(!res || WrappedID3D11Texture1D::IsAlloc(res) || WrappedID3D11Texture2D1::IsAlloc(res) || + WrappedID3D11Texture3D1::IsAlloc(res) || WrappedID3D11Buffer::IsAlloc(res)); +#endif + + resource = res; + minMip = mip; + maxMip = mip; + minSlice = slice; + maxSlice = slice; + fullRange = false; + depthReadOnly = false; + stencilReadOnly = false; +} + TextureDim MakeTextureDim(D3D11_SRV_DIMENSION dim) { switch(dim) @@ -661,11 +727,17 @@ static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, switch(type.descriptor.type) { + case DXBC::VARTYPE_MIN12INT: + case DXBC::VARTYPE_MIN16INT: case DXBC::VARTYPE_INT: ret.descriptor.type = VarType::Int; break; case DXBC::VARTYPE_BOOL: + case DXBC::VARTYPE_MIN16UINT: case DXBC::VARTYPE_UINT: ret.descriptor.type = VarType::UInt; break; case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = VarType::Double; break; case DXBC::VARTYPE_FLOAT: + case DXBC::VARTYPE_MIN8FLOAT: + case DXBC::VARTYPE_MIN10FLOAT: + case DXBC::VARTYPE_MIN16FLOAT: default: ret.descriptor.type = VarType::Float; break; } ret.descriptor.rows = type.descriptor.rows; diff --git a/renderdoc/driver/d3d11/d3d11_common.h b/renderdoc/driver/d3d11/d3d11_common.h index 00a9bec360..05d8d298bc 100644 --- a/renderdoc/driver/d3d11/d3d11_common.h +++ b/renderdoc/driver/d3d11/d3d11_common.h @@ -51,43 +51,34 @@ struct D3D11MarkerRegion struct ResourceRange { - static ResourceRange Null; - - ResourceRange(ID3D11Buffer *res) +private: + enum Empty { - resource = res; - minMip = minSlice = 0; - maxMip = allMip; - maxSlice = allSlice; - fullRange = true; - depthReadOnly = false; - stencilReadOnly = false; - } + empty + }; - ResourceRange(ID3D11Texture2D *res) + // used to initialise Null below + ResourceRange(Empty) { - resource = res; - minMip = minSlice = 0; - maxMip = allMip; - maxSlice = allSlice; - fullRange = true; + resource = NULL; + minMip = 0; + maxMip = 0; + minSlice = 0; + maxSlice = 0; + fullRange = false; depthReadOnly = false; stencilReadOnly = false; } +public: + static ResourceRange Null; + + ResourceRange(ID3D11Buffer *res); + ResourceRange(ID3D11Texture2D *res); + // construct a range for a specific mip/slice. Used for easily checking if // a view includes this mip/slice - ResourceRange(ID3D11Resource *res, UINT mip, UINT slice) - { - resource = res; - minMip = mip; - maxMip = mip; - minSlice = slice; - maxSlice = slice; - fullRange = false; - depthReadOnly = false; - stencilReadOnly = false; - } + ResourceRange(ID3D11Resource *res, UINT mip, UINT slice); // initialises the range with the contents of the view ResourceRange(ID3D11ShaderResourceView *srv); diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 69ec0235fb..d1438a7def 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -1030,15 +1030,15 @@ void WrappedID3D11DeviceContext::AddEvent(string description) m_Events.push_back(apievent); } -APIEvent WrappedID3D11DeviceContext::GetEvent(uint32_t eventID) +const APIEvent &WrappedID3D11DeviceContext::GetEvent(uint32_t eventID) { - for(size_t i = m_Events.size() - 1; i > 0; i--) + for(const APIEvent &e : m_Events) { - if(m_Events[i].eventID <= eventID) - return m_Events[i]; + if(e.eventID >= eventID) + return e; } - return m_Events[0]; + return m_Events.back(); } void WrappedID3D11DeviceContext::ReplayFakeContext(ResourceId id) @@ -1969,38 +1969,48 @@ void WrappedID3D11DeviceContext::RecordOutputMergerStats(UINT NumRTVs, ID3D11Ren // #mivance is an elaborate redundancy here even useful? // const D3D11RenderState::outmerger* Current = &m_CurrentPipelineState->OM; - if(RTVs != NULL) + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) { - for(UINT index = 0; index < NumRTVs; index++) + if(RTVs != NULL) { - outputs.sets += (RTVs[index] != NULL); - outputs.nulls += (RTVs[index] == NULL); + for(UINT index = 0; index < NumRTVs; index++) + { + outputs.sets += (RTVs[index] != NULL); + outputs.nulls += (RTVs[index] == NULL); + } + } + else + { + outputs.nulls += NumRTVs; } - } - else if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) - { - outputs.nulls += NumRTVs; } outputs.sets += (DSV != NULL); outputs.nulls += (DSV == NULL); - if(UAVs != NULL) + if(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) { - for(UINT index = 0; index < NumUAVs; index++) + if(UAVs != NULL) { - outputs.sets += (UAVs[index] != NULL); - outputs.nulls += (UAVs[index] == NULL); + for(UINT index = 0; index < NumUAVs; index++) + { + outputs.sets += (UAVs[index] != NULL); + outputs.nulls += (UAVs[index] == NULL); + } + } + else + { + outputs.nulls += NumUAVs; } } - else - { - outputs.nulls += NumUAVs; - } - UINT NumSlots = NumRTVs + NumUAVs; - if(NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) - NumSlots = NumUAVs; + UINT NumSlots = 0; + + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + NumSlots += NumRTVs; + if(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) + NumSlots += NumUAVs; + RDCASSERT(NumSlots < outputs.bindslots.size()); outputs.bindslots[NumSlots] += 1; } diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h index 2d6b0386c9..d88577e929 100644 --- a/renderdoc/driver/d3d11/d3d11_context.h +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -316,7 +316,7 @@ class WrappedID3D11DeviceContext : public RefCounter, public ID3D11DeviceContext void ClearMaps(); uint32_t GetEventID() { return m_CurEventID; } - APIEvent GetEvent(uint32_t eventID); + const APIEvent &GetEvent(uint32_t eventID); const DrawcallTreeNode &GetRootDraw() { return m_ParentDrawcall; } void ThreadSafe_SetMarker(uint32_t col, const wchar_t *name); diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index 206f557bad..b773473955 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -3392,7 +3392,12 @@ void WrappedID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( // D3D11 doesn't seem to complain about this case, but it messes our render state tracking so // ensure we don't blat over any RTs with 'empty' UAVs. if(NumUAVs == 0) - UAVStartSlot = RDCMAX(NumRTVs, UAVStartSlot); + { + if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) + UAVStartSlot = RDCMAX(NumRTVs, UAVStartSlot); + else + UAVStartSlot = RDCMAX(m_CurrentPipelineState->OM.UAVStartSlot, UAVStartSlot); + } if(m_State == WRITING_CAPFRAME) { @@ -3408,10 +3413,13 @@ void WrappedID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT] = {0}; - for(UINT i = 0; ppRenderTargetViews && i < NumRTVs; i++) + for(UINT i = 0; + ppRenderTargetViews && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL && i < NumRTVs; + i++) RTs[i] = ppRenderTargetViews[i]; - for(UINT i = 0; ppUnorderedAccessViews && i < NumUAVs; i++) + for(UINT i = 0; + ppUnorderedAccessViews && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS && i < NumUAVs; i++) UAVs[i] = ppUnorderedAccessViews[i]; if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) @@ -3478,7 +3486,9 @@ void WrappedID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( RDCMIN(NumUAVs, D3D11_1_UAV_SLOT_COUNT - StartSlot)); } - for(UINT i = 0; ppRenderTargetViews && i < NumRTVs; i++) + for(UINT i = 0; + ppRenderTargetViews && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL && i < NumRTVs; + i++) { if(ppRenderTargetViews[i] && m_State >= WRITING) { @@ -3494,7 +3504,8 @@ void WrappedID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, ppRenderTargetViews[i]); } - for(UINT i = 0; ppUnorderedAccessViews && i < NumUAVs; i++) + for(UINT i = 0; + ppUnorderedAccessViews && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS && i < NumUAVs; i++) { if(ppUnorderedAccessViews[i] && m_State >= WRITING) { @@ -4843,6 +4854,11 @@ bool WrappedID3D11DeviceContext::Serialise_ExecuteCommandList(ID3D11CommandList { SAFE_DELETE(m_DeferredSavedState); m_DeferredSavedState = new D3D11RenderState(this); + + // From the Docs: + // "Immediate context state is cleared before and after a command list is executed. A command + // list has no concept of inheritance." + ClearState(); } if(m_State == READING) diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 6eb0847441..e37e94f5c6 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -213,16 +213,7 @@ D3D11DebugManager::~D3D11DebugManager() elem.Release(); m_ShaderItemCache.pop_back(); } - - for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) - { - SAFE_RELEASE(it->second.vsout.buf); - SAFE_RELEASE(it->second.vsout.idxBuf); - SAFE_RELEASE(it->second.gsout.buf); - SAFE_RELEASE(it->second.gsout.idxBuf); - } - - m_PostVSData.clear(); + ClearPostVSCache(); SAFE_RELEASE(m_pImmediateContext); m_WrappedDevice->InternalRelease(); @@ -3584,7 +3575,7 @@ bool D3D11DebugManager::RenderTexture(TextureDisplay cfg, bool blendAlpha) if(details.texType == eTexType_3D) { pixelData.OutputDisplayFormat = RESTYPE_TEX3D; - pixelData.Slice = float(cfg.sliceFace); + pixelData.Slice = float(cfg.sliceFace >> cfg.mip); } else if(details.texType == eTexType_1D) { @@ -3809,6 +3800,19 @@ void D3D11DebugManager::RenderCheckerboard(Vec3f light, Vec3f dark) } } +void D3D11DebugManager::ClearPostVSCache() +{ + for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) + { + SAFE_RELEASE(it->second.vsout.buf); + SAFE_RELEASE(it->second.vsout.idxBuf); + SAFE_RELEASE(it->second.gsout.buf); + SAFE_RELEASE(it->second.gsout.idxBuf); + } + + m_PostVSData.clear(); +} + MeshFormat D3D11DebugManager::GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage) { D3D11PostVSData postvs; diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 084ed3f3ba..9b9808737d 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -130,6 +130,7 @@ class D3D11DebugManager int GetHeight() { return m_height; } void InitPostVSBuffers(uint32_t eventID); MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); + void ClearPostVSCache(); uint32_t GetStructCount(ID3D11UnorderedAccessView *uav); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, vector &retData); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 72541e66d9..d3cae9c3a3 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1498,6 +1498,7 @@ byte *D3D11Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mi void D3D11Replay::ReplaceResource(ResourceId from, ResourceId to) { m_pDevice->GetResourceManager()->ReplaceResource(from, to); + m_pDevice->GetDebugManager()->ClearPostVSCache(); } void D3D11Replay::RemoveReplacement(ResourceId id) diff --git a/renderdoc/driver/d3d11/d3d11_resources.h b/renderdoc/driver/d3d11/d3d11_resources.h index f1244941c0..108781dbfb 100644 --- a/renderdoc/driver/d3d11/d3d11_resources.h +++ b/renderdoc/driver/d3d11/d3d11_resources.h @@ -747,7 +747,7 @@ class WrappedView1 : public WrappedDeviceChild11 ResourceRange m_ResourceRange; WrappedView1(NestedType *real, WrappedID3D11Device *device, ID3D11Resource *res) - : WrappedDeviceChild11(real, device), m_pResource(res), m_ResourceRange(real) + : WrappedDeviceChild11(real, device), m_pResource(res), m_ResourceRange(this) { m_ResourceResID = GetIDForResource(m_pResource); // cast is potentially invalid but functions in WrappedResource will be identical across each diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index adcd8f301e..538a812462 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -118,7 +118,7 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue, WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; } const vector &GetCmdLists() { return m_CmdListRecords; } D3D12DrawcallTreeNode &GetParentDrawcall() { return m_Cmd.m_ParentDrawcall; } - APIEvent GetEvent(uint32_t eventID); + const APIEvent &GetEvent(uint32_t eventID); uint32_t GetMaxEID() { return m_Cmd.m_Events.back().eventID; } ResourceId GetBackbufferResourceID() { return m_BackbufferID; } void ClearAfterCapture(); diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index 42a5fc2995..46f261b99d 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -254,15 +254,15 @@ void WrappedID3D12CommandQueue::ClearAfterCapture() m_QueueRecord->DeleteChunks(); } -APIEvent WrappedID3D12CommandQueue::GetEvent(uint32_t eventID) +const APIEvent &WrappedID3D12CommandQueue::GetEvent(uint32_t eventID) { - for(size_t i = m_Cmd.m_Events.size() - 1; i > 0; i--) + for(const APIEvent &e : m_Cmd.m_Events) { - if(m_Cmd.m_Events[i].eventID <= eventID) - return m_Cmd.m_Events[i]; + if(e.eventID >= eventID) + return e; } - return m_Cmd.m_Events[0]; + return m_Cmd.m_Events.back(); } void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chunk) diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index fb4ffccd59..05f8947919 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -371,11 +371,17 @@ static ShaderVariableType MakeShaderVariableType(DXBC::CBufferVariableType type, switch(type.descriptor.type) { + case DXBC::VARTYPE_MIN12INT: + case DXBC::VARTYPE_MIN16INT: case DXBC::VARTYPE_INT: ret.descriptor.type = VarType::Int; break; case DXBC::VARTYPE_BOOL: + case DXBC::VARTYPE_MIN16UINT: case DXBC::VARTYPE_UINT: ret.descriptor.type = VarType::UInt; break; case DXBC::VARTYPE_DOUBLE: ret.descriptor.type = VarType::Double; break; case DXBC::VARTYPE_FLOAT: + case DXBC::VARTYPE_MIN8FLOAT: + case DXBC::VARTYPE_MIN10FLOAT: + case DXBC::VARTYPE_MIN16FLOAT: default: ret.descriptor.type = VarType::Float; break; } ret.descriptor.rows = type.descriptor.rows; diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 8f5e9e3851..a50ead5317 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -1279,14 +1279,6 @@ D3D12DebugManager::~D3D12DebugManager() for(size_t p = 0; p < MeshDisplayPipelines::ePipe_Count; p++) SAFE_RELEASE(it->second.pipes[p]); - for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) - { - SAFE_RELEASE(it->second.vsout.buf); - SAFE_RELEASE(it->second.vsout.idxBuf); - SAFE_RELEASE(it->second.gsout.buf); - SAFE_RELEASE(it->second.gsout.idxBuf); - } - SAFE_RELEASE(m_pFactory); SAFE_RELEASE(dsvHeap); @@ -2916,11 +2908,17 @@ void D3D12DebugManager::FillCBufferVariables(const string &prefix, size_t &offse 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: type = VarType::UInt; break; + case VARTYPE_UINT8: + case VARTYPE_MIN16UINT: type = VarType::UInt; break; case VARTYPE_DOUBLE: elemByteSize = 8; type = VarType::Double; @@ -3796,6 +3794,19 @@ byte *D3D12DebugManager::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint3 return ret; } +void D3D12DebugManager::ClearPostVSCache() +{ + for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) + { + SAFE_RELEASE(it->second.vsout.buf); + SAFE_RELEASE(it->second.vsout.idxBuf); + SAFE_RELEASE(it->second.gsout.buf); + SAFE_RELEASE(it->second.gsout.idxBuf); + } + + m_PostVSData.clear(); +} + void D3D12DebugManager::InitPostVSBuffers(uint32_t eventID) { // go through any aliasing @@ -8026,7 +8037,7 @@ bool D3D12DebugManager::RenderTextureInternal(D3D12_CPU_DESCRIPTOR_HANDLE rtv, T pixelData.Slice = float(RDCCLAMP(cfg.sliceFace, 0U, uint32_t(resourceDesc.DepthOrArraySize - 1))); if(resourceDesc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE3D) - pixelData.Slice = float(cfg.sliceFace); + pixelData.Slice = float(cfg.sliceFace >> cfg.mip); vector barriers; int resType = 0; diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 8c59660fe6..f0512a0a40 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -100,6 +100,7 @@ class D3D12DebugManager // indicates that EID alias is the same as eventID void AliasPostVSBuffers(uint32_t eventID, uint32_t alias) { m_PostVSAlias[alias] = eventID; } MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); + void ClearPostVSCache(); void GetBufferData(ResourceId buff, uint64_t offset, uint64_t length, vector &retData); void GetBufferData(ID3D12Resource *buff, uint64_t offset, uint64_t length, vector &retData); diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index e044f03cc1..1ff1e717f1 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -164,6 +164,12 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D return; } } + else if(!nonsamp.resource) + { + // if we don't have a resource (which is possible if the descriptor is unused), use a + // default descriptor + desc = defaultSRV(); + } // it's possible to end up with invalid resource and descriptor combinations: // 1. descriptor is created for ResID_1234 BC1_TYPELESS and a view BC1_UNORM @@ -211,6 +217,50 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D } } + D3D12_SHADER_RESOURCE_VIEW_DESC planeDesc; + // ensure that multi-plane formats have a valid plane slice specified. This shouldn't be + // possible as it should be the application's responsibility to be valid too, but we fix it up + // here anyway. + if(nonsamp.resource) + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = desc->Format; + dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo)); + + // if this format is multi-plane + if(formatInfo.PlaneCount > 1) + { + planeDesc = *desc; + desc = &planeDesc; + + // detect formats that only read plane 1 and set the planeslice to 1 + if(desc->Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT || + desc->Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT) + { + switch(planeDesc.ViewDimension) + { + case D3D12_SRV_DIMENSION_TEXTURE2D: planeDesc.Texture2D.PlaneSlice = 1; break; + case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: + planeDesc.Texture2DArray.PlaneSlice = 1; + break; + default: break; + } + } + else + { + // otherwise set it to 0 + switch(planeDesc.ViewDimension) + { + case D3D12_SRV_DIMENSION_TEXTURE2D: planeDesc.Texture2D.PlaneSlice = 0; break; + case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: + planeDesc.Texture2DArray.PlaneSlice = 0; + break; + default: break; + } + } + } + } + dev->CreateShaderResourceView(nonsamp.resource, desc, handle); break; } @@ -235,6 +285,12 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D return; } } + else if(!nonsamp.resource) + { + // if we don't have a resource (which is possible if the descriptor is unused), use a + // default descriptor + desc = defaultRTV(); + } // see comment above in SRV case for what this code is doing if(nonsamp.resource && desc) @@ -263,6 +319,50 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D } } + D3D12_RENDER_TARGET_VIEW_DESC planeDesc; + // ensure that multi-plane formats have a valid plane slice specified. This shouldn't be + // possible as it should be the application's responsibility to be valid too, but we fix it up + // here anyway. + if(nonsamp.resource) + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = desc->Format; + dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo)); + + // if this format is multi-plane + if(formatInfo.PlaneCount > 1) + { + planeDesc = *desc; + desc = &planeDesc; + + // detect formats that only read plane 1 and set the planeslice to 1 + if(desc->Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT || + desc->Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT) + { + switch(planeDesc.ViewDimension) + { + case D3D12_RTV_DIMENSION_TEXTURE2D: planeDesc.Texture2D.PlaneSlice = 1; break; + case D3D12_RTV_DIMENSION_TEXTURE2DARRAY: + planeDesc.Texture2DArray.PlaneSlice = 1; + break; + default: break; + } + } + else + { + // otherwise set it to 0 + switch(planeDesc.ViewDimension) + { + case D3D12_RTV_DIMENSION_TEXTURE2D: planeDesc.Texture2D.PlaneSlice = 0; break; + case D3D12_RTV_DIMENSION_TEXTURE2DARRAY: + planeDesc.Texture2DArray.PlaneSlice = 0; + break; + default: break; + } + } + } + } + dev->CreateRenderTargetView(nonsamp.resource, desc, handle); break; } @@ -270,7 +370,15 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D { D3D12_DEPTH_STENCIL_VIEW_DESC *desc = &nonsamp.dsv; if(desc->ViewDimension == D3D12_DSV_DIMENSION_UNKNOWN) + { desc = nonsamp.resource ? NULL : defaultDSV(); + } + else if(!nonsamp.resource) + { + // if we don't have a resource (which is possible if the descriptor is unused), use a + // default descriptor + desc = defaultDSV(); + } // see comment above in SRV case for what this code is doing if(nonsamp.resource && desc) @@ -325,6 +433,12 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D return; } } + else if(!nonsamp.resource) + { + // if we don't have a resource (which is possible if the descriptor is unused), use a + // default descriptor + desc = defaultUAV(); + } // don't create a UAV with a counter resource but no main resource. This is fine because // if the main resource wasn't present in the capture, this UAV isn't present - the counter @@ -363,6 +477,50 @@ void D3D12Descriptor::Create(D3D12_DESCRIPTOR_HEAP_TYPE heapType, WrappedID3D12D } } + D3D12_UNORDERED_ACCESS_VIEW_DESC planeDesc; + // ensure that multi-plane formats have a valid plane slice specified. This shouldn't be + // possible as it should be the application's responsibility to be valid too, but we fix it up + // here anyway. + if(nonsamp.resource) + { + D3D12_FEATURE_DATA_FORMAT_INFO formatInfo = {}; + formatInfo.Format = desc->Format; + dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, &formatInfo, sizeof(formatInfo)); + + // if this format is multi-plane + if(formatInfo.PlaneCount > 1) + { + planeDesc = *desc; + desc = &planeDesc; + + // detect formats that only read plane 1 and set the planeslice to 1 + if(desc->Format == DXGI_FORMAT_X24_TYPELESS_G8_UINT || + desc->Format == DXGI_FORMAT_X32_TYPELESS_G8X24_UINT) + { + switch(planeDesc.ViewDimension) + { + case D3D12_UAV_DIMENSION_TEXTURE2D: planeDesc.Texture2D.PlaneSlice = 1; break; + case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: + planeDesc.Texture2DArray.PlaneSlice = 1; + break; + default: break; + } + } + else + { + // otherwise set it to 0 + switch(planeDesc.ViewDimension) + { + case D3D12_UAV_DIMENSION_TEXTURE2D: planeDesc.Texture2D.PlaneSlice = 0; break; + case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: + planeDesc.Texture2DArray.PlaneSlice = 0; + break; + default: break; + } + } + } + } + dev->CreateUnorderedAccessView(nonsamp.resource, counter, desc, handle); break; } diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index 2e4044e5b8..5756e81a18 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -1645,6 +1645,8 @@ void D3D12Replay::ReplaceResource(ResourceId from, ResourceId to) rm->ReplaceResource(from, to); } + + m_pDevice->GetDebugManager()->ClearPostVSCache(); } void D3D12Replay::RemoveReplacement(ResourceId id) diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 8197452071..33204fe0a3 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -161,7 +161,6 @@ struct GLWindowingData egl_ctx = 0; egl_dpy = 0; egl_wnd = 0; - wnd = 0; } void SetCtx(void *c) { egl_ctx = (void *)c; } @@ -172,8 +171,11 @@ struct GLWindowingData EGLContext egl_ctx; }; EGLDisplay egl_dpy; - EGLSurface egl_wnd; - ANativeWindow *wnd; + union + { + EGLSurface egl_wnd; + void *wnd; + }; }; #else diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 1c3d1fab13..4914cec8b5 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -45,7 +45,7 @@ GLuint GLReplay::CreateCShaderProgram(const vector &csSources) MakeCurrentReplayContext(m_DebugCtx); - WrappedOpenGL &gl = *m_pDriver; + const GLHookSet &gl = m_pDriver->GetHookset(); GLuint cs = gl.glCreateShader(eGL_COMPUTE_SHADER); @@ -102,7 +102,7 @@ GLuint GLReplay::CreateShaderProgram(const vector &vsSources, MakeCurrentReplayContext(m_DebugCtx); - WrappedOpenGL &gl = *m_pDriver; + const GLHookSet &gl = m_pDriver->GetHookset(); GLuint vs = 0; GLuint fs = 0; @@ -734,15 +734,7 @@ void GLReplay::DeleteDebugData() MakeCurrentReplayContext(m_DebugCtx); - for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) - { - gl.glDeleteBuffers(1, &it->second.vsout.buf); - gl.glDeleteBuffers(1, &it->second.vsout.idxBuf); - gl.glDeleteBuffers(1, &it->second.gsout.buf); - gl.glDeleteBuffers(1, &it->second.gsout.idxBuf); - } - - m_PostVSData.clear(); + ClearPostVSCache(); gl.glDeleteFramebuffers(1, &DebugData.overlayFBO); gl.glDeleteTextures(1, &DebugData.overlayTex); @@ -3149,7 +3141,13 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, CompType typeHint, DebugOve gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); - gl.glFramebufferTexture(eGL_FRAMEBUFFER, eGL_DEPTH_STENCIL_ATTACHMENT, quadtexs[1], 0); + + GLenum dsAttach = eGL_DEPTH_STENCIL_ATTACHMENT; + + if(GetBaseFormat(fmt) == eGL_DEPTH_COMPONENT) + dsAttach = eGL_DEPTH_ATTACHMENT; + + gl.glFramebufferTexture(eGL_FRAMEBUFFER, dsAttach, quadtexs[1], 0); if(overlay == DebugOverlay::QuadOverdrawPass) ReplayLog(events[0], eReplay_WithoutDraw); @@ -3306,6 +3304,21 @@ ResourceId GLReplay::RenderOverlay(ResourceId texid, CompType typeHint, DebugOve return m_pDriver->GetResourceManager()->GetID(TextureRes(ctx, DebugData.overlayTex)); } +void GLReplay::ClearPostVSCache() +{ + WrappedOpenGL &gl = *m_pDriver; + + for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) + { + gl.glDeleteBuffers(1, &it->second.vsout.buf); + gl.glDeleteBuffers(1, &it->second.vsout.idxBuf); + gl.glDeleteBuffers(1, &it->second.gsout.buf); + gl.glDeleteBuffers(1, &it->second.gsout.idxBuf); + } + + m_PostVSData.clear(); +} + void GLReplay::InitPostVSBuffers(uint32_t eventID) { if(m_PostVSData.find(eventID) != m_PostVSData.end()) @@ -3622,7 +3635,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventID) if(!(drawcall->flags & DrawFlags::UseIBuffer)) { - uint32_t outputSize = drawcall->numIndices * drawcall->numInstances * stride; + uint32_t outputSize = drawcall->numIndices * stride; if(drawcall->flags & DrawFlags::Instanced) outputSize *= drawcall->numInstances; @@ -3735,7 +3748,7 @@ void GLReplay::InitPostVSBuffers(uint32_t eventID) gl.glNamedBufferDataEXT(indexSetBuffer, sizeof(uint32_t) * indices.size(), &indices[0], eGL_STATIC_DRAW); - uint32_t outputSize = (uint32_t)indices.size() * drawcall->numInstances * stride; + uint32_t outputSize = (uint32_t)indices.size() * stride; if(drawcall->flags & DrawFlags::Instanced) outputSize *= drawcall->numInstances; diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 3254e9f4ef..265e7c514d 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -2975,15 +2975,17 @@ WrappedOpenGL::BackbufferImage *WrappedOpenGL::SaveBackbufferImage() m_Real.glPixelStorei(eGL_PACK_ALIGNMENT, prevPackAlignment); // scale down if necessary using simple point sampling - if(thwidth > maxSize) + uint32_t resample_width = RDCMIN(maxSize, thwidth); + resample_width &= ~3; // JPEG encoder gives shear distortion if width is not divisible by 4. + if(thwidth != resample_width) { float widthf = float(thwidth); float heightf = float(thheight); float aspect = widthf / heightf; - // clamp dimensions to a width of maxSize - thwidth = maxSize; + // clamp dimensions to a width of resample_width + thwidth = resample_width; thheight = uint32_t(float(thwidth) / aspect); byte *src = thpixels; @@ -4462,15 +4464,15 @@ void WrappedOpenGL::AddEvent(string description) m_Events.push_back(apievent); } -APIEvent WrappedOpenGL::GetEvent(uint32_t eventID) +const APIEvent &WrappedOpenGL::GetEvent(uint32_t eventID) { - for(size_t i = m_Events.size() - 1; i > 0; i--) + for(const APIEvent &e : m_Events) { - if(m_Events[i].eventID <= eventID) - return m_Events[i]; + if(e.eventID >= eventID) + return e; } - return m_Events[0]; + return m_Events.back(); } const DrawcallDescription *WrappedOpenGL::GetDrawcall(uint32_t eventID) diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 4ac92f760d..3bcd70ae97 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -574,7 +574,7 @@ class WrappedOpenGL : public IFrameCapturer GLuint GetFakeBBFBO() { return m_FakeBB_FBO; } GLuint GetFakeVAO() { return m_FakeVAO; } FrameRecord &GetFrameRecord() { return m_FrameRecord; } - APIEvent GetEvent(uint32_t eventID); + const APIEvent &GetEvent(uint32_t eventID); const DrawcallTreeNode &GetRootDraw() { return m_ParentDrawcall; } const DrawcallDescription *GetDrawcall(uint32_t eventID); diff --git a/renderdoc/driver/gl/gl_hooks_egl.cpp b/renderdoc/driver/gl/gl_hooks_egl.cpp index bc5cf90d29..832475c706 100644 --- a/renderdoc/driver/gl/gl_hooks_egl.cpp +++ b/renderdoc/driver/gl/gl_hooks_egl.cpp @@ -276,9 +276,6 @@ class EGLHook : LibraryHook, public GLPlatform ret.egl_dpy = eglDisplay; ret.egl_ctx = ctx; ret.egl_wnd = surface; -#if ENABLED(RDOC_ANDROID) - ret.wnd = (ANativeWindow *)window; -#endif return ret; } diff --git a/renderdoc/driver/gl/gl_hooks_linux.cpp b/renderdoc/driver/gl/gl_hooks_linux.cpp index ed79f2935c..0c632121c0 100644 --- a/renderdoc/driver/gl/gl_hooks_linux.cpp +++ b/renderdoc/driver/gl/gl_hooks_linux.cpp @@ -42,6 +42,7 @@ typedef XVisualInfo *(*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display *dpy, GLXFBConfi typedef int (*PFNGLXGETCONFIGPROC)(Display *dpy, XVisualInfo *vis, int attrib, int *value); typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display *dpy, int *errorBase, int *eventBase); typedef Bool (*PFNGLXISDIRECTPROC)(Display *dpy, GLXContext ctx); +typedef __GLXextFuncPtr (*PFNGLXGETPROCADDRESSARBPROC)(const GLubyte *procName); class OpenGLHook : LibraryHook, public GLPlatform { @@ -252,6 +253,8 @@ class OpenGLHook : LibraryHook, public GLPlatform RDCERR("Unexpected window system %u", system); } + // GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB MUST be the last attrib so that we can remove it to retry + // if we find no srgb fbconfigs static int visAttribs[] = {GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, @@ -271,9 +274,26 @@ class OpenGLHook : LibraryHook, public GLPlatform GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True, 0}; + int numCfgs = 0; GLXFBConfig *fbcfg = glXChooseFBConfig_real(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + if(fbcfg == NULL) + { + const size_t len = ARRAY_COUNT(visAttribs); + if(visAttribs[len - 3] != GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB) + { + RDCERR( + "GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB isn't the last attribute, and no SRGB fbconfigs were " + "found!"); + } + else + { + visAttribs[len - 3] = 0; + fbcfg = glXChooseFBConfig_real(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + } + } + if(fbcfg == NULL) { RDCERR("Couldn't choose default framebuffer config"); @@ -363,6 +383,7 @@ class OpenGLHook : LibraryHook, public GLPlatform PFNGLXDESTROYCONTEXTPROC glXDestroyContext_real; PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB_real; PFNGLXGETPROCADDRESSPROC glXGetProcAddress_real; + PFNGLXGETPROCADDRESSARBPROC glXGetProcAddressARB_real; PFNGLXMAKECURRENTPROC glXMakeCurrent_real; PFNGLXMAKECONTEXTCURRENTPROC glXMakeContextCurrent_real; PFNGLXSWAPBUFFERSPROC glXSwapBuffers_real; @@ -388,6 +409,9 @@ class OpenGLHook : LibraryHook, public GLPlatform if(glXGetProcAddress_real == NULL) glXGetProcAddress_real = (PFNGLXGETPROCADDRESSPROC)dlsym(libGLdlsymHandle, "glXGetProcAddress"); + if(glXGetProcAddressARB_real == NULL) + glXGetProcAddressARB_real = + (PFNGLXGETPROCADDRESSPROC)dlsym(libGLdlsymHandle, "glXGetProcAddressARB"); if(glXCreateContext_real == NULL) glXCreateContext_real = (PFNGLXCREATECONTEXTPROC)dlsym(libGLdlsymHandle, "glXCreateContext"); if(glXDestroyContext_real == NULL) @@ -418,6 +442,15 @@ class OpenGLHook : LibraryHook, public GLPlatform if(glXQueryDrawable_real == NULL) glXQueryDrawable_real = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable"); + // glXCreateContextAttribsARB may not be directly exported by libGL.so, so try to fetch it + // through the glXGetProcAddress function, favouring the ARB variant. + if(glXCreateContextAttribsARB_real == NULL && glXGetProcAddressARB_real) + glXCreateContextAttribsARB_real = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB_real( + (const GLubyte *)"glXCreateContextAttribsARB"); + if(glXCreateContextAttribsARB_real == NULL && glXGetProcAddress_real) + glXCreateContextAttribsARB_real = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress_real( + (const GLubyte *)"glXCreateContextAttribsARB"); + return success; } diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp index f889d731e7..2e46e98dbf 100644 --- a/renderdoc/driver/gl/gl_manager.cpp +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -24,6 +24,7 @@ ******************************************************************************/ #include "driver/gl/gl_manager.h" +#include #include "driver/gl/gl_driver.h" struct VertexAttribInitialData @@ -1069,12 +1070,32 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) GLuint initProg = gl.glCreateProgram(); + std::vector vertexOutputs; for(size_t i = 0; i < details.shaders.size(); i++) { const auto &shadDetails = m_GL->m_Shaders[details.shaders[i]]; GLuint shad = gl.glCreateShader(shadDetails.type); + if(shadDetails.type == eGL_VERTEX_SHADER) + { + for(int s = 0; s < shadDetails.reflection.OutputSig.count; s++) + { + std::string name = shadDetails.reflection.OutputSig[s].varName.c_str(); + + // look for :row added to split up matrix variables + size_t colon = name.find(":row"); + + // remove it, if present + if(colon != std::string::npos) + name.resize(colon); + + // only push matrix variables once + if(std::find(vertexOutputs.begin(), vertexOutputs.end(), name) == vertexOutputs.end()) + vertexOutputs.push_back(name); + } + } + char **srcs = new char *[shadDetails.sources.size()]; for(size_t s = 0; s < shadDetails.sources.size(); s++) srcs[s] = (char *)shadDetails.sources[s].c_str(); @@ -1086,11 +1107,32 @@ bool GLResourceManager::Serialise_InitialState(ResourceId resid, GLResource res) gl.glDeleteShader(shad); } + // Some drivers optimize out uniforms if they dont change any active vertex shader outputs. + // This resulted in initProg locationTranslate table being -1 for a particular shader where + // some uniforms were only intended to affect TF. Therefore set a TF mode for all varyings. + // As the initial state program is never used for TF, this wont adversely affect anything. + + std::vector vertexOutputsPtr; + vertexOutputsPtr.resize(vertexOutputs.size()); + for(size_t i = 0; i < vertexOutputs.size(); i++) + vertexOutputsPtr[i] = vertexOutputs[i].c_str(); + gl.glTransformFeedbackVaryings(initProg, (GLsizei)vertexOutputsPtr.size(), + &vertexOutputsPtr[0], eGL_INTERLEAVED_ATTRIBS); gl.glLinkProgram(initProg); GLint status = 0; gl.glGetProgramiv(initProg, eGL_LINK_STATUS, &status); + // if it failed to link, first remove the varyings hack above as maybe the driver is barfing + // on trying to make some output a varying + if(status == 0) + { + gl.glTransformFeedbackVaryings(initProg, 0, NULL, eGL_INTERLEAVED_ATTRIBS); + gl.glLinkProgram(initProg); + + gl.glGetProgramiv(initProg, eGL_LINK_STATUS, &status); + } + // if it failed to link, try again as a separable program. // we can't do this by default because of the silly rules meaning // shaders need fixup to be separable-compatible. diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index f05b551e50..d07f25796f 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -223,8 +223,8 @@ void GLReplay::CreateOutputWindowBackbuffer(OutputWindow &outwin, bool depth) gl.glGenTextures(1, &outwin.BlitData.backbuffer); gl.glBindTexture(eGL_TEXTURE_2D, outwin.BlitData.backbuffer); - gl.glTextureImage2DEXT(outwin.BlitData.backbuffer, eGL_TEXTURE_2D, 0, eGL_SRGB8, outwin.width, - outwin.height, 0, eGL_RGB, eGL_UNSIGNED_BYTE, NULL); + gl.glTextureImage2DEXT(outwin.BlitData.backbuffer, eGL_TEXTURE_2D, 0, eGL_SRGB8_ALPHA8, + outwin.width, outwin.height, 0, eGL_RGBA, eGL_UNSIGNED_BYTE, NULL); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAX_LEVEL, 0); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); @@ -2948,6 +2948,7 @@ void GLReplay::ReplaceResource(ResourceId from, ResourceId to) { MakeCurrentReplayContext(&m_ReplayCtx); m_pDriver->ReplaceResource(from, to); + ClearPostVSCache(); } void GLReplay::RemoveReplacement(ResourceId id) diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 78ea2a4e2d..70eebbc953 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -370,6 +370,8 @@ class GLReplay : public IReplayDriver // eventID -> data map m_PostVSData; + void ClearPostVSCache(); + // cache the previous data returned ResourceId m_GetTexturePrevID; byte *m_GetTexturePrevData[16]; diff --git a/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp index fbfa8273c4..323dbd7ec0 100644 --- a/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_buffer_funcs.cpp @@ -4181,8 +4181,8 @@ bool WrappedOpenGL::Serialise_glVertexArrayVertexBuffers(GLuint vaobj, GLuint fi buffers && buffers[i] ? GetResourceManager()->GetID(BufferRes(GetCtx(), buffers[i])) : ResourceId()); - SERIALISE_ELEMENT(uint64_t, offset, buffers ? 0 : (uint64_t)offsets[i]); - SERIALISE_ELEMENT(uint64_t, stride, buffers ? 0 : (uint64_t)strides[i]); + SERIALISE_ELEMENT(uint64_t, offset, buffers ? (uint64_t)offsets[i] : 0); + SERIALISE_ELEMENT(uint64_t, stride, buffers ? (uint64_t)strides[i] : 0); if(m_State <= EXECUTING) { diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index c01b34677d..36a9ce4104 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -379,7 +379,15 @@ void *APIENTRY _glMapNamedBufferEXT(GLuint buffer, GLenum access) PushPopBuffer(eGL_COPY_READ_BUFFER, buffer); GLint size; hookset->glGetBufferParameteriv(eGL_COPY_READ_BUFFER, eGL_BUFFER_SIZE, &size); - return hookset->glMapBufferRange(eGL_COPY_READ_BUFFER, 0, size, eGL_MAP_READ_BIT); + + GLbitfield accessBits = eGL_MAP_READ_BIT | eGL_MAP_WRITE_BIT; + + if(access == eGL_READ_ONLY) + accessBits = eGL_MAP_READ_BIT; + else if(access == eGL_WRITE_ONLY) + accessBits = eGL_MAP_WRITE_BIT; + + return hookset->glMapBufferRange(eGL_COPY_READ_BUFFER, 0, size, accessBits); } void *APIENTRY _glMapNamedBufferRangeEXT(GLuint buffer, GLintptr offset, GLsizeiptr length, diff --git a/renderdoc/driver/ihv/amd/AMD.vcxproj b/renderdoc/driver/ihv/amd/AMD.vcxproj index b8875c3348..1999bd24f2 100644 --- a/renderdoc/driver/ihv/amd/AMD.vcxproj +++ b/renderdoc/driver/ihv/amd/AMD.vcxproj @@ -127,6 +127,11 @@ + + + {0aae0ad1-371b-4a36-9ed1-80e10e960605} + + diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index ccac64b471..a059a4fa40 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -39,12 +39,12 @@ namespace ShaderDebug { static float round_ne(float x) { - // if on 0.5 boundary - if(int(x + 0.5f) != int(x)) - return int(x) % 2 == 0 ? float(int(x)) : float(int(x + 1)); + if(!_finite(x) || _isnan(x)) + return x; - // normal round - return x < 0 ? x + 0.5f : x; + float rem = remainderf(x, 1.0f); + + return x - rem; } VarType State::OperationType(const OpcodeType &op) const @@ -2545,6 +2545,7 @@ State State::GetNext(GlobalState &global, State quad[4]) const fmt.byteWidth = 4; fmt.numComps = global.groupshared[resIndex].bytestride / 4; fmt.reversed = false; + fmt.stride = 0; } texData = false; } @@ -2555,7 +2556,7 @@ State State::GetNext(GlobalState &global, State quad[4]) const if(texData) { - texOffset += texCoords[0] * fmt.byteWidth * fmt.numComps; + texOffset += texCoords[0] * fmt.Stride(); texOffset += texCoords[1] * rowPitch; texOffset += texCoords[2] * depthPitch; } diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.h b/renderdoc/driver/shaders/dxbc/dxbc_debug.h index 183f2f0d46..4c462d2a5c 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.h @@ -57,21 +57,17 @@ struct GlobalState struct ViewFmt { - ViewFmt() - { - byteWidth = 0; - numComps = 0; - reversed = false; - fmt = CompType::Typeless; - } - - int byteWidth; - int numComps; - bool reversed; - CompType fmt; + int byteWidth = 0; + int numComps = 0; + bool reversed = false; + CompType fmt = CompType::Typeless; + int stride = 0; int Stride() { + if(stride != 0) + return stride; + if(byteWidth == 10 || byteWidth == 11) return 32; // 10 10 10 2 or 11 11 10 diff --git a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp index e4edd019d6..8c46450851 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp @@ -294,6 +294,47 @@ void DXBCFile::FetchTypeVersion() m_Version.Minor = VersionToken::MinorVersion.Get(cur[0]); } +void DXBCFile::FetchThreadDim() +{ + if(m_HexDump.empty()) + return; + + uint32_t *begin = &m_HexDump.front(); + uint32_t *cur = begin; + uint32_t *end = &m_HexDump.back(); + + // skip header dword above + cur++; + + // skip length dword + cur++; + + while(cur < end) + { + uint32_t OpcodeToken0 = cur[0]; + + OpcodeType op = Opcode::Type.Get(OpcodeToken0); + + if(op == OPCODE_DCL_THREAD_GROUP) + { + DispatchThreadsDimension[0] = cur[1]; + DispatchThreadsDimension[1] = cur[2]; + DispatchThreadsDimension[2] = cur[3]; + break; + } + + if(op == OPCODE_CUSTOMDATA) + { + // length in opcode token is 0, full length is in second dword + cur += cur[1]; + } + else + { + cur += Opcode::Length.Get(OpcodeToken0); + } + } +} + void DXBCFile::DisassembleHexDump() { if(m_Disassembled) @@ -1338,13 +1379,17 @@ string ASMOperand::toString(DXBCFile *dxbc, ToString flags) const { str += " {"; if(precision == PRECISION_FLOAT10) - str += "min2_8f as def32"; + str += "min10f"; if(precision == PRECISION_FLOAT16) - str += "min16f as def32"; + str += "min16f"; if(precision == PRECISION_UINT16) str += "min16u"; if(precision == PRECISION_SINT16) str += "min16i"; + if(precision == PRECISION_ANY16) + str += "any16"; + if(precision == PRECISION_ANY10) + str += "any10"; str += "}"; } diff --git a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h index 262952ad8b..b43d8b3828 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h @@ -490,8 +490,11 @@ enum MinimumPrecision PRECISION_DEFAULT, PRECISION_FLOAT16, PRECISION_FLOAT10, + PRECISION_UNUSED, PRECISION_SINT16, PRECISION_UINT16, + PRECISION_ANY16, + PRECISION_ANY10, NUM_PRECISIONS, }; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp index 8468eee53d..f068b5d137 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp @@ -205,6 +205,13 @@ struct SIGNElement7 SIGNElement elem; }; +struct SIGNElement1 +{ + uint32_t stream; + SIGNElement elem; + MinimumPrecision precision; +}; + static const uint32_t STATSizeDX10 = 29 * 4; // either 29 uint32s static const uint32_t STATSizeDX11 = 37 * 4; // or 37 uint32s @@ -218,6 +225,8 @@ static const uint32_t FOURCC_SDBG = MAKE_FOURCC('S', 'D', 'B', 'G'); static const uint32_t FOURCC_SPDB = MAKE_FOURCC('S', 'P', 'D', 'B'); static const uint32_t FOURCC_ISGN = MAKE_FOURCC('I', 'S', 'G', 'N'); static const uint32_t FOURCC_OSGN = MAKE_FOURCC('O', 'S', 'G', 'N'); +static const uint32_t FOURCC_ISG1 = MAKE_FOURCC('I', 'S', 'G', '1'); +static const uint32_t FOURCC_OSG1 = MAKE_FOURCC('O', 'S', 'G', '1'); static const uint32_t FOURCC_OSG5 = MAKE_FOURCC('O', 'S', 'G', '5'); static const uint32_t FOURCC_PCSG = MAKE_FOURCC('P', 'C', 'S', 'G'); static const uint32_t FOURCC_Aon9 = MAKE_FOURCC('A', 'o', 'n', '9'); @@ -231,7 +240,16 @@ int TypeByteSize(VariableType t) case VARTYPE_BOOL: case VARTYPE_INT: case VARTYPE_FLOAT: - case VARTYPE_UINT: return 4; + case VARTYPE_UINT: + return 4; + // we pretend for our purposes that the 'min' formats round up to 4 bytes. For any external + // interfaces they are treated as regular types, only using lower precision internally. + case VARTYPE_MIN8FLOAT: + case VARTYPE_MIN10FLOAT: + case VARTYPE_MIN16FLOAT: + case VARTYPE_MIN12INT: + case VARTYPE_MIN16INT: + case VARTYPE_MIN16UINT: return 4; case VARTYPE_DOUBLE: return 8; // 'virtual' type. Just return 1 @@ -286,6 +304,12 @@ string TypeName(CBufferVariableType::Descriptor desc) case VARTYPE_UINT8: type = "ubyte"; break; case VARTYPE_VOID: type = "void"; break; case VARTYPE_INTERFACE_POINTER: type = "interface"; break; + case VARTYPE_MIN8FLOAT: type = "min8float"; break; + case VARTYPE_MIN10FLOAT: type = "min10float"; break; + case VARTYPE_MIN16FLOAT: type = "min16float"; break; + case VARTYPE_MIN12INT: type = "min12int"; break; + case VARTYPE_MIN16INT: type = "min16int"; break; + case VARTYPE_MIN16UINT: type = "min16uint"; break; default: RDCERR("Unexpected type in RDEF variable type %d", type); } @@ -823,6 +847,12 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) m_GuessedResources = true; } + // make sure to fetch the dispatch threads dimension from disassembly + if(!m_Disassembled && m_Type == D3D11_ShaderType_Compute) + { + FetchThreadDim(); + } + for(uint32_t chunkIdx = 0; chunkIdx < header->numChunks; chunkIdx++) { uint32_t *fourcc = (uint32_t *)(data + chunkOffsets[chunkIdx]); @@ -830,8 +860,8 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) char *chunkContents = (char *)(data + chunkOffsets[chunkIdx] + sizeof(uint32_t) * 2); - if(*fourcc == FOURCC_ISGN || *fourcc == FOURCC_OSGN || *fourcc == FOURCC_OSG5 || - *fourcc == FOURCC_PCSG) + if(*fourcc == FOURCC_ISGN || *fourcc == FOURCC_OSGN || *fourcc == FOURCC_ISG1 || + *fourcc == FOURCC_OSG1 || *fourcc == FOURCC_OSG5 || *fourcc == FOURCC_PCSG) { SIGNHeader *sign = (SIGNHeader *)fourcc; @@ -841,12 +871,12 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) bool output = false; bool patch = false; - if(*fourcc == FOURCC_ISGN) + if(*fourcc == FOURCC_ISGN || *fourcc == FOURCC_ISG1) { sig = &m_InputSig; input = true; } - if(*fourcc == FOURCC_OSGN || *fourcc == FOURCC_OSG5) + if(*fourcc == FOURCC_OSGN || *fourcc == FOURCC_OSG1 || *fourcc == FOURCC_OSG5) { sig = &m_OutputSig; output = true; @@ -861,11 +891,22 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) SIGNElement *el = (SIGNElement *)(sign + 1); SIGNElement7 *el7 = (SIGNElement7 *)el; + SIGNElement1 *el1 = (SIGNElement1 *)el; for(uint32_t signIdx = 0; signIdx < sign->numElems; signIdx++) { SigParameter desc; + if(*fourcc == FOURCC_ISG1 || *fourcc == FOURCC_OSG1) + { + desc.stream = el1->stream; + + // discard el1->precision as we don't use it and don't want to pollute the common API + // structures + + el = &el1->elem; + } + if(*fourcc == FOURCC_OSG5) { desc.stream = el7->stream; @@ -956,6 +997,7 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) sig->push_back(desc); el++; + el1++; el7++; } @@ -1087,6 +1129,10 @@ void DXBCFile::GuessResources() } desc.numSamples = dcl.sampleCount; + // can't tell, fxc seems to default to 4 + if(desc.dimension == ShaderInputBind::DIM_BUFFER) + desc.numSamples = 4; + RDCASSERT(desc.dimension != ShaderInputBind::DIM_UNKNOWN); if(dcl.operand.indices.size() == 3) diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h index 0ff2daaf5a..c621d75409 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h @@ -109,6 +109,12 @@ enum VariableType VARTYPE_RWSTRUCTURED_BUFFER, VARTYPE_APPEND_STRUCTURED_BUFFER, VARTYPE_CONSUME_STRUCTURED_BUFFER, + VARTYPE_MIN8FLOAT, + VARTYPE_MIN10FLOAT, + VARTYPE_MIN16FLOAT, + VARTYPE_MIN12INT, + VARTYPE_MIN16INT, + VARTYPE_MIN16UINT, }; struct ShaderInputBind @@ -399,6 +405,7 @@ class DXBCFile DXBCFile(const DXBCFile &o); DXBCFile &operator=(const DXBCFile &o); + void FetchThreadDim(); void FetchTypeVersion(); void DisassembleHexDump(); void MakeDisassemblyString(); diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index 1ce4fb1932..ff3a1bc2df 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -3825,14 +3825,14 @@ void AddSignatureParameter(bool isInput, ShaderStage stage, uint32_t id, sig.regChannelMask = sig.channelUsedMask = (1 << type->vectorSize) - 1; + // arrays will need an extra access chain index + if(isArray) + patch.accessChain.push_back(0U); + for(uint32_t a = 0; a < arraySize; a++) { string n = varName; - // arrays will need an extra access chain index - if(arraySize > 1) - patch.accessChain.push_back(0U); - if(isArray) { n = StringFormat::Fmt("%s[%u]", varName.c_str(), a); @@ -3866,7 +3866,7 @@ void AddSignatureParameter(bool isInput, ShaderStage stage, uint32_t id, } sig.regIndex += RDCMAX(1U, type->matrixSize); - if(arraySize > 1) + if(isArray) patch.accessChain.back()++; } } diff --git a/renderdoc/driver/vulkan/CMakeLists.txt b/renderdoc/driver/vulkan/CMakeLists.txt index 9ddd2ba7de..27f913f4a9 100644 --- a/renderdoc/driver/vulkan/CMakeLists.txt +++ b/renderdoc/driver/vulkan/CMakeLists.txt @@ -40,11 +40,17 @@ set(sources set(definitions ${RDOC_DEFINITIONS}) +set(VULKAN_LAYER_FOLDER_DEFAULT /etc/vulkan/implicit_layer.d) + +if(NOT ANDROID AND NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND NOT DEFINED VULKAN_LAYER_FOLDER) + message(WARNING "*** CMAKE_INSTALL_PREFIX has been customised to ${CMAKE_INSTALL_PREFIX}, but VULKAN_LAYER_FOLDER is not customised and defaults to ${VULKAN_LAYER_FOLDER_DEFAULT}. This may not do what you expect, e.g. installing to a non-root location ***") +endif() + # This must be specified separately because it needs to go in /etc regardless of what the install # prefix is, since the loader only looks in a set location (and /usr/share is reserved for distribution # packages). For people who want to 'make install' to another folder, perhaps for preparing a package, # they can set this variable to make sure it stays local -set(VULKAN_LAYER_FOLDER /etc/vulkan/implicit_layer.d CACHE PATH "Path to install the vulkan layer file") +set(VULKAN_LAYER_FOLDER ${VULKAN_LAYER_FOLDER_DEFAULT} CACHE PATH "Path to install the vulkan layer file") if(ANDROID) list(APPEND sources vk_posix.cpp vk_android.cpp vk_layer_android.cpp) diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 52d3563e50..65c544f7c3 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -2809,9 +2809,9 @@ void WrappedVulkan::AddDrawcall(const DrawcallDescription &d, bool hasEvents) vector &colAtt = m_CreationInfo.m_RenderPass[rp].subpasses[sp].colorAttachments; int32_t dsAtt = m_CreationInfo.m_RenderPass[rp].subpasses[sp].depthstencilAttachment; - RDCASSERT(colAtt.size() < 8); + RDCASSERT(colAtt.size() <= ARRAY_COUNT(draw.outputs)); - for(int i = 0; i < 8 && i < (int)colAtt.size(); i++) + for(size_t i = 0; i < ARRAY_COUNT(draw.outputs) && i < colAtt.size(); i++) { if(colAtt[i] == VK_ATTACHMENT_UNUSED) continue; @@ -3108,15 +3108,15 @@ void WrappedVulkan::AddEvent(string description) m_EventMessages.clear(); } -APIEvent WrappedVulkan::GetEvent(uint32_t eventID) +const APIEvent &WrappedVulkan::GetEvent(uint32_t eventID) { - for(size_t i = m_Events.size() - 1; i > 0; i--) + for(const APIEvent &e : m_Events) { - if(m_Events[i].eventID <= eventID) - return m_Events[i]; + if(e.eventID >= eventID) + return e; } - return m_Events[0]; + return m_Events.back(); } const DrawcallDescription *WrappedVulkan::GetDrawcall(uint32_t eventID) diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 4e126092d0..d75cffaf71 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -472,6 +472,13 @@ class WrappedVulkan : public IFrameCapturer ePartialNum }; + struct Submission + { + Submission(uint32_t eid) : baseEvent(eid), rebased(false) {} + uint32_t baseEvent = 0; + bool rebased = false; + }; + struct PartialReplayData { PartialReplayData() { Reset(); } @@ -512,8 +519,12 @@ class WrappedVulkan : public IFrameCapturer // vkCmd chunks) is NOT unique. // However, a single baked command list can be submitted multiple // times - so we have to have a list of base events - // Map from bakeID -> vector - map > cmdBufferSubmits; + // Note in the case of secondary command buffers we mark when these + // are rebased to 'absolute' event IDs, since they could be submitted + // multiple times in the frame and we don't want to rebase all of + // them each time. + // Map from bakeID -> vector + map > cmdBufferSubmits; // This is just the ResourceId of the original parent command buffer // and it's baked id. @@ -713,7 +724,7 @@ class WrappedVulkan : public IFrameCapturer void ReadLogInitialisation(); FrameRecord &GetFrameRecord() { return m_FrameRecord; } - APIEvent GetEvent(uint32_t eventID); + const APIEvent &GetEvent(uint32_t eventID); uint32_t GetMaxEID() { return m_Events.back().eventID; } const DrawcallDescription *GetDrawcall(uint32_t eventID); diff --git a/renderdoc/driver/vulkan/vk_counters.cpp b/renderdoc/driver/vulkan/vk_counters.cpp index ab3d3449ee..79ed298107 100644 --- a/renderdoc/driver/vulkan/vk_counters.cpp +++ b/renderdoc/driver/vulkan/vk_counters.cpp @@ -281,15 +281,38 @@ vector VulkanReplay::FetchCounters(const vector &coun ObjDisp(dev)->CreateQueryPool(Unwrap(dev), &timeStampPoolCreateInfo, NULL, &timeStampPool); RDCASSERTEQUAL(vkr, VK_SUCCESS); + bool occlNeeded = false; + bool statsNeeded = false; + + for(size_t c = 0; c < counters.size(); c++) + { + switch(counters[c]) + { + case GPUCounter::InputVerticesRead: + case GPUCounter::IAPrimitives: + case GPUCounter::GSPrimitives: + case GPUCounter::RasterizerInvocations: + case GPUCounter::RasterizedPrimitives: + case GPUCounter::VSInvocations: + case GPUCounter::TCSInvocations: + case GPUCounter::TESInvocations: + case GPUCounter::GSInvocations: + case GPUCounter::PSInvocations: + case GPUCounter::CSInvocations: statsNeeded = true; break; + case GPUCounter::SamplesWritten: occlNeeded = true; break; + default: break; + } + } + VkQueryPool occlusionPool = VK_NULL_HANDLE; - if(availableFeatures.occlusionQueryPrecise) + if(availableFeatures.occlusionQueryPrecise && occlNeeded) { vkr = ObjDisp(dev)->CreateQueryPool(Unwrap(dev), &occlusionPoolCreateInfo, NULL, &occlusionPool); RDCASSERTEQUAL(vkr, VK_SUCCESS); } VkQueryPool pipeStatsPool = VK_NULL_HANDLE; - if(availableFeatures.pipelineStatisticsQuery) + if(availableFeatures.pipelineStatisticsQuery && statsNeeded) { vkr = ObjDisp(dev)->CreateQueryPool(Unwrap(dev), &pipeStatsPoolCreateInfo, NULL, &pipeStatsPool); RDCASSERTEQUAL(vkr, VK_SUCCESS); diff --git a/renderdoc/driver/vulkan/vk_debug.cpp b/renderdoc/driver/vulkan/vk_debug.cpp index 3f87339be6..f38c1cb99e 100644 --- a/renderdoc/driver/vulkan/vk_debug.cpp +++ b/renderdoc/driver/vulkan/vk_debug.cpp @@ -2507,15 +2507,7 @@ VulkanDebugManager::~VulkanDebugManager() ShaderCacheCallbacks.Destroy(it->second); } - for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) - { - m_pDriver->vkDestroyBuffer(dev, it->second.vsout.buf, NULL); - m_pDriver->vkDestroyBuffer(dev, it->second.vsout.idxBuf, NULL); - m_pDriver->vkFreeMemory(dev, it->second.vsout.bufmem, NULL); - m_pDriver->vkFreeMemory(dev, it->second.vsout.idxBufMem, NULL); - } - - m_PostVSData.clear(); + ClearPostVSCache(); // since we don't have properly registered resources, releasing our descriptor // pool here won't remove the descriptor sets, so we need to free our own @@ -7917,6 +7909,21 @@ static void AddOutputDumping(const ShaderReflection &refl, const SPIRVPatchData spirv[3] = idBound; } +void VulkanDebugManager::ClearPostVSCache() +{ + VkDevice dev = m_Device; + + for(auto it = m_PostVSData.begin(); it != m_PostVSData.end(); ++it) + { + m_pDriver->vkDestroyBuffer(dev, it->second.vsout.buf, NULL); + m_pDriver->vkDestroyBuffer(dev, it->second.vsout.idxBuf, NULL); + m_pDriver->vkFreeMemory(dev, it->second.vsout.bufmem, NULL); + m_pDriver->vkFreeMemory(dev, it->second.vsout.idxBufMem, NULL); + } + + m_PostVSData.clear(); +} + void VulkanDebugManager::InitPostVSBuffers(uint32_t eventID) { // go through any aliasing diff --git a/renderdoc/driver/vulkan/vk_debug.h b/renderdoc/driver/vulkan/vk_debug.h index ff1a8d6c0a..c376246fcd 100644 --- a/renderdoc/driver/vulkan/vk_debug.h +++ b/renderdoc/driver/vulkan/vk_debug.h @@ -120,6 +120,8 @@ class VulkanDebugManager // indicates that EID alias is the same as eventID void AliasPostVSBuffers(uint32_t eventID, uint32_t alias) { m_PostVSAlias[alias] = eventID; } MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage); + void ClearPostVSCache(); + void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector &ret); uint32_t PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y, uint32_t w, diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index 7f2867b0d1..832c1cf1c5 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -282,8 +282,7 @@ CheckExt(VK_EXT_direct_mode_display); \ CheckExt(VK_EXT_acquire_xlib_display); \ CheckExt(VK_KHR_external_memory_capabilities); \ - CheckExt(VK_KHR_external_semaphore_capabilities); \ - CheckExt(VK_KHR_get_memory_requirements2); + CheckExt(VK_KHR_external_semaphore_capabilities); #define CheckDeviceExts() \ CheckExt(VK_EXT_debug_marker); \ @@ -299,7 +298,8 @@ CheckExt(VK_KHR_external_memory_fd); \ CheckExt(VK_KHR_external_semaphore); \ CheckExt(VK_KHR_external_semaphore_win32); \ - CheckExt(VK_KHR_external_semaphore_fd); + CheckExt(VK_KHR_external_semaphore_fd); \ + CheckExt(VK_KHR_get_memory_requirements2); #define HookInitVulkanInstanceExts() \ HookInitExtension(VK_KHR_surface, DestroySurfaceKHR); \ diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 20c072a2bd..5e4b0cec88 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -254,6 +254,9 @@ struct VulkanCreationInfo vector attachments; uint32_t width, height, layers; + + // See above in loadRPs - we need to duplicate and make framebuffer equivalents for each + vector loadFBs; }; map m_Framebuffer; diff --git a/renderdoc/driver/vulkan/vk_posix.cpp b/renderdoc/driver/vulkan/vk_posix.cpp index af7ed30e82..ec54320623 100644 --- a/renderdoc/driver/vulkan/vk_posix.cpp +++ b/renderdoc/driver/vulkan/vk_posix.cpp @@ -157,7 +157,6 @@ VkBool32 WrappedVulkan::vkGetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalD namespace Keyboard { void UseConnection(xcb_connection_t *conn); -void CloneDisplay(Display *dpy); } VkResult WrappedVulkan::vkCreateXcbSurfaceKHR(VkInstance instance, @@ -199,6 +198,11 @@ VkBool32 WrappedVulkan::vkGetPhysicalDeviceXlibPresentationSupportKHR( visualID); } +namespace Keyboard +{ +void CloneDisplay(Display *dpy); +} + VkResult WrappedVulkan::vkCreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index fed463d8f8..8db0ae5194 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -3820,7 +3820,7 @@ bool VulkanReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, data->HistogramTextureResolution.x = (float)RDCMAX(uint32_t(iminfo.extent.width) >> mip, 1U); data->HistogramTextureResolution.y = (float)RDCMAX(uint32_t(iminfo.extent.height) >> mip, 1U); - data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.arrayLayers) >> mip, 1U); + data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.extent.depth) >> mip, 1U); if(iminfo.type != VK_IMAGE_TYPE_3D) data->HistogramSlice = (float)sliceFace + 0.001f; else @@ -4065,7 +4065,7 @@ bool VulkanReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t m data->HistogramTextureResolution.x = (float)RDCMAX(uint32_t(iminfo.extent.width) >> mip, 1U); data->HistogramTextureResolution.y = (float)RDCMAX(uint32_t(iminfo.extent.height) >> mip, 1U); - data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.arrayLayers) >> mip, 1U); + data->HistogramTextureResolution.z = (float)RDCMAX(uint32_t(iminfo.extent.depth) >> mip, 1U); if(iminfo.type != VK_IMAGE_TYPE_3D) data->HistogramSlice = (float)sliceFace + 0.001f; else @@ -4352,6 +4352,14 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m imCreateInfo.extent.height = RDCMAX(1U, imCreateInfo.extent.height >> mip); imCreateInfo.extent.depth = RDCMAX(1U, imCreateInfo.extent.depth >> mip); + // convert a 3D texture into a 2D array, so we can render to the slices without needing + // KHR_maintenance1 + if(imCreateInfo.extent.depth > 1) + { + imCreateInfo.arrayLayers = imCreateInfo.extent.depth; + imCreateInfo.extent.depth = 1; + } + // create render texture similar to readback texture vt->CreateImage(Unwrap(dev), &imCreateInfo, NULL, &tmpImage); @@ -4427,7 +4435,7 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m }; vt->CreateRenderPass(Unwrap(dev), &rpinfo, NULL, &tmpRP); - numFBs = (imCreateInfo.imageType == VK_IMAGE_TYPE_3D ? (imCreateInfo.extent.depth >> mip) : 1); + numFBs = imCreateInfo.arrayLayers; tmpFB = new VkFramebuffer[numFBs]; tmpView = new VkImageView[numFBs]; @@ -4439,6 +4447,12 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m // if 3d texture, render each slice separately, otherwise render once for(uint32_t i = 0; i < numFBs; i++) { + if(numFBs > 1 && (i % GetDebugManager()->m_TexDisplayUBO.GetRingCount()) == 0) + { + m_pDriver->SubmitCmds(); + m_pDriver->FlushQ(); + } + TextureDisplay texDisplay; texDisplay.Red = texDisplay.Green = texDisplay.Blue = texDisplay.Alpha = true; @@ -4447,10 +4461,9 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m texDisplay.overlay = DebugOverlay::NoOverlay; texDisplay.FlipY = false; texDisplay.mip = mip; - texDisplay.sampleIdx = - imCreateInfo.imageType == VK_IMAGE_TYPE_3D ? 0 : (params.resolve ? ~0U : arrayIdx); + texDisplay.sampleIdx = imInfo.type == VK_IMAGE_TYPE_3D ? 0 : (params.resolve ? ~0U : arrayIdx); texDisplay.CustomShader = ResourceId(); - texDisplay.sliceFace = imCreateInfo.imageType == VK_IMAGE_TYPE_3D ? i : arrayIdx; + texDisplay.sliceFace = imInfo.type == VK_IMAGE_TYPE_3D ? i : arrayIdx; texDisplay.rangemin = params.blackPoint; texDisplay.rangemax = params.whitePoint; texDisplay.scale = 1.0f; @@ -4872,6 +4885,18 @@ byte *VulkanReplay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t m vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, readbackBuf, 2, copyregion); } + else if(imInfo.type == VK_IMAGE_TYPE_3D && params.remap) + { + // copy in each slice from the 2D array we created to render out the 3D texture + for(uint32_t i = 0; i < imCreateInfo.arrayLayers; i++) + { + copyregion[0].imageSubresource.baseArrayLayer = i; + copyregion[0].bufferOffset = + i * GetByteSize(imInfo.extent.width, imInfo.extent.height, 1, imCreateInfo.format, mip); + vt->CmdCopyImageToBuffer(Unwrap(cmd), srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + readbackBuf, 1, copyregion); + } + } else { // copy from desired subresource in srcImage to buffer @@ -5192,6 +5217,7 @@ void VulkanReplay::BuildTargetShader(string source, string entry, const uint32_t void VulkanReplay::ReplaceResource(ResourceId from, ResourceId to) { GetDebugManager()->ReplaceResource(from, to); + GetDebugManager()->ClearPostVSCache(); } void VulkanReplay::RemoveReplacement(ResourceId id) @@ -5277,6 +5303,12 @@ ReplayStatus Vulkan_CreateReplayDevice(const char *logfile, IReplayDriver **driv // disable the layer env var, just in case the user left it set from a previous capture run Process::RegisterEnvironmentModification( EnvironmentModification(EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "0")); + + // disable buggy and user-hostile NV optimus layer, which can completely delete physical devices + // (not just rearrange them) and cause problems between capture and replay. + Process::RegisterEnvironmentModification( + EnvironmentModification(EnvMod::Set, EnvSep::NoSep, "DISABLE_LAYER_NV_OPTIMUS_1", "")); + Process::ApplyEnvironmentModification(); void *module = Process::LoadModule(VulkanLibraryName); diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index f4a186e413..0e6efabb0f 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -99,7 +99,7 @@ void VulkanRenderState::BeginRenderPassAndApplyState(VkCommandBuffer cmd, Pipeli VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, NULL, Unwrap(m_CreationInfo->m_RenderPass[renderPass].loadRPs[subpass]), - Unwrap(GetResourceManager()->GetCurrentHandle(framebuffer)), + Unwrap(m_CreationInfo->m_Framebuffer[framebuffer].loadFBs[subpass]), renderArea, (uint32_t)m_CreationInfo->m_RenderPass[renderPass].attachments.size(), empty, diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index 2a1135c943..320c35f7e2 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -513,19 +513,19 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(Serialiser *localSerialiser, // check for partial execution of this command buffer for(int p = 0; p < ePartialNum; p++) { - const vector &baseEvents = m_Partial[p].cmdBufferSubmits[bakeId]; + const vector &submissions = m_Partial[p].cmdBufferSubmits[bakeId]; - for(auto it = baseEvents.begin(); it != baseEvents.end(); ++it) + for(auto it = submissions.begin(); it != submissions.end(); ++it) { - if(*it <= m_LastEventID && m_LastEventID < (*it + length)) + if(it->baseEvent <= m_LastEventID && m_LastEventID < (it->baseEvent + length)) { #if ENABLED(VERBOSE_PARTIAL_REPLAY) - RDCDEBUG("vkBegin - partial detected %u < %u < %u, %llu -> %llu", *it, m_LastEventID, - *it + length, cmdId, bakeId); + RDCDEBUG("vkBegin - partial detected %u < %u < %u, %llu -> %llu", it->baseEvent, + m_LastEventID, it->baseEvent + length, cmdId, bakeId); #endif m_Partial[p].partialParent = cmdId; - m_Partial[p].baseEvent = *it; + m_Partial[p].baseEvent = it->baseEvent; m_Partial[p].renderPassActive = false; m_Partial[p].partialDevice = device; m_Partial[p].resultPartialCmdPool = @@ -1166,53 +1166,57 @@ bool WrappedVulkan::Serialise_vkCmdBindPipeline(Serialiser *localSerialiser, ResourceId liveid = GetResID(pipeline); - if(bind == VK_PIPELINE_BIND_POINT_GRAPHICS) - m_RenderState.graphics.pipeline = liveid; - else - m_RenderState.compute.pipeline = liveid; - - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_VIEWPORT]) - { - m_RenderState.views = m_CreationInfo.m_Pipeline[liveid].viewports; - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_SCISSOR]) - { - m_RenderState.scissors = m_CreationInfo.m_Pipeline[liveid].scissors; - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_LINE_WIDTH]) - { - m_RenderState.lineWidth = m_CreationInfo.m_Pipeline[liveid].lineWidth; - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_DEPTH_BIAS]) + if(bind == VK_PIPELINE_BIND_POINT_COMPUTE) { - m_RenderState.bias.depth = m_CreationInfo.m_Pipeline[liveid].depthBiasConstantFactor; - m_RenderState.bias.biasclamp = m_CreationInfo.m_Pipeline[liveid].depthBiasClamp; - m_RenderState.bias.slope = m_CreationInfo.m_Pipeline[liveid].depthBiasSlopeFactor; - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_BLEND_CONSTANTS]) - { - memcpy(m_RenderState.blendConst, m_CreationInfo.m_Pipeline[liveid].blendConst, - sizeof(float) * 4); - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_DEPTH_BOUNDS]) - { - m_RenderState.mindepth = m_CreationInfo.m_Pipeline[liveid].minDepthBounds; - m_RenderState.maxdepth = m_CreationInfo.m_Pipeline[liveid].maxDepthBounds; - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]) - { - m_RenderState.front.compare = m_CreationInfo.m_Pipeline[liveid].front.compareMask; - m_RenderState.back.compare = m_CreationInfo.m_Pipeline[liveid].back.compareMask; - } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]) - { - m_RenderState.front.write = m_CreationInfo.m_Pipeline[liveid].front.writeMask; - m_RenderState.back.write = m_CreationInfo.m_Pipeline[liveid].back.writeMask; + m_RenderState.compute.pipeline = liveid; } - if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_STENCIL_REFERENCE]) + else { - m_RenderState.front.ref = m_CreationInfo.m_Pipeline[liveid].front.reference; - m_RenderState.back.ref = m_CreationInfo.m_Pipeline[liveid].back.reference; + m_RenderState.graphics.pipeline = liveid; + + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_VIEWPORT]) + { + m_RenderState.views = m_CreationInfo.m_Pipeline[liveid].viewports; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_SCISSOR]) + { + m_RenderState.scissors = m_CreationInfo.m_Pipeline[liveid].scissors; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_LINE_WIDTH]) + { + m_RenderState.lineWidth = m_CreationInfo.m_Pipeline[liveid].lineWidth; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_DEPTH_BIAS]) + { + m_RenderState.bias.depth = m_CreationInfo.m_Pipeline[liveid].depthBiasConstantFactor; + m_RenderState.bias.biasclamp = m_CreationInfo.m_Pipeline[liveid].depthBiasClamp; + m_RenderState.bias.slope = m_CreationInfo.m_Pipeline[liveid].depthBiasSlopeFactor; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_BLEND_CONSTANTS]) + { + memcpy(m_RenderState.blendConst, m_CreationInfo.m_Pipeline[liveid].blendConst, + sizeof(float) * 4); + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_DEPTH_BOUNDS]) + { + m_RenderState.mindepth = m_CreationInfo.m_Pipeline[liveid].minDepthBounds; + m_RenderState.maxdepth = m_CreationInfo.m_Pipeline[liveid].maxDepthBounds; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK]) + { + m_RenderState.front.compare = m_CreationInfo.m_Pipeline[liveid].front.compareMask; + m_RenderState.back.compare = m_CreationInfo.m_Pipeline[liveid].back.compareMask; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_STENCIL_WRITE_MASK]) + { + m_RenderState.front.write = m_CreationInfo.m_Pipeline[liveid].front.writeMask; + m_RenderState.back.write = m_CreationInfo.m_Pipeline[liveid].back.writeMask; + } + if(!m_CreationInfo.m_Pipeline[liveid].dynamicStates[VK_DYNAMIC_STATE_STENCIL_REFERENCE]) + { + m_RenderState.front.ref = m_CreationInfo.m_Pipeline[liveid].front.reference; + m_RenderState.back.ref = m_CreationInfo.m_Pipeline[liveid].back.reference; + } } } } @@ -1330,6 +1334,7 @@ bool WrappedVulkan::Serialise_vkCmdBindDescriptorSets( descsets[first + i].descSet = descriptorIDs[i]; uint32_t dynCount = m_CreationInfo.m_DescSetLayout[descSetLayouts[first + i]].dynamicCount; descsets[first + i].offsets.assign(offsIter, offsIter + dynCount); + offsIter += dynCount; dynConsumed += dynCount; RDCASSERT(dynConsumed <= offsCount); } diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index b5a859547c..e7315056c3 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -663,6 +663,11 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, VkBufferView *bufViews = (VkBufferView *)bufInfos; nextDescriptors += pDescriptorWrites[i].descriptorCount; + RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkDescriptorImageInfo), + "Structure sizes mean not enough space is allocated for write data"); + RDCCOMPILE_ASSERT(sizeof(VkDescriptorBufferInfo) >= sizeof(VkBufferView), + "Structure sizes mean not enough space is allocated for write data"); + // unwrap and assign the appropriate array if(pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER) @@ -677,11 +682,22 @@ void WrappedVulkan::vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT) { + bool hasSampler = + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || + pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + bool hasImage = + (pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER || + pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || + pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE || + pDescriptorWrites[i].descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT); + unwrappedWrites[i].pImageInfo = (VkDescriptorImageInfo *)bufInfos; for(uint32_t j = 0; j < pDescriptorWrites[i].descriptorCount; j++) { - imInfos[j].imageView = Unwrap(pDescriptorWrites[i].pImageInfo[j].imageView); - imInfos[j].sampler = Unwrap(pDescriptorWrites[i].pImageInfo[j].sampler); + if(hasImage) + imInfos[j].imageView = Unwrap(pDescriptorWrites[i].pImageInfo[j].imageView); + if(hasSampler) + imInfos[j].sampler = Unwrap(pDescriptorWrites[i].pImageInfo[j].sampler); imInfos[j].imageLayout = pDescriptorWrites[i].pImageInfo[j].imageLayout; } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index a5001abb41..2458f1c6af 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -672,7 +672,11 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(Serialiser *localSerial pd = m_ReplayPhysicalDevices[bestIdx]; - GetResourceManager()->AddLiveResource(physId, pd); + if(!m_ReplayPhysicalDevicesUsed[bestIdx]) + GetResourceManager()->AddLiveResource(physId, pd); + else + GetResourceManager()->ReplaceResource(physId, + GetResourceManager()->GetOriginalID(GetResID(pd))); if(physIndex >= m_PhysicalDevices.size()) m_PhysicalDevices.resize(physIndex + 1); @@ -682,16 +686,22 @@ bool WrappedVulkan::Serialise_vkEnumeratePhysicalDevices(Serialiser *localSerial { // error if we're remapping multiple physical devices to the same best match RDCERR( - "Mappnig multiple capture-time physical devices to a single replay-time physical device." + "Mapping multiple capture-time physical devices to a single replay-time physical device." "This means the HW has changed between capture and replay and may cause bugs."); } - else + else if(m_MemIdxMaps[bestIdx] == NULL) { // the first physical device 'wins' for the memory index map uint32_t *storedMap = new uint32_t[32]; memcpy(storedMap, memIdxMap, sizeof(memIdxMap)); - m_MemIdxMaps[physIndex] = storedMap; + + for(uint32_t i = 0; i < 32; i++) + storedMap[i] = i; + + m_MemIdxMaps[bestIdx] = storedMap; } + + m_ReplayPhysicalDevicesUsed[bestIdx] = true; } return true; @@ -888,13 +898,12 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, for(uint32_t i = 0; i < createInfo.enabledExtensionCount; i++) { // don't include the debug marker extension - if(strcmp(createInfo.ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) + if(!strcmp(createInfo.ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) continue; // don't include direct-display WSI extensions - if(strcmp(createInfo.ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) || - strcmp(createInfo.ppEnabledExtensionNames[i], VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME) || - strcmp(createInfo.ppEnabledExtensionNames[i], VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME)) + if(!strcmp(createInfo.ppEnabledExtensionNames[i], VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME) || + !strcmp(createInfo.ppEnabledExtensionNames[i], VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME)) continue; Extensions.push_back(createInfo.ppEnabledExtensionNames[i]); diff --git a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp index 34c8bcabd2..6fc09bf04d 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_draw_funcs.cpp @@ -82,7 +82,7 @@ bool WrappedVulkan::Serialise_vkCmdDraw(Serialiser *localSerialiser, VkCommandBu if(m_State == EXECUTING) { - if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && m_RenderState.renderPass != ResourceId()) + if(ShouldRerecordCmd(cmdid) && InRerecordRange(cmdid) && IsDrawInRenderPass()) { commandBuffer = RerecordCmdBuf(cmdid); diff --git a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp index 3ca68405c4..cb4ec7ed82 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_get_funcs.cpp @@ -160,6 +160,30 @@ void WrappedVulkan::vkGetImageMemoryRequirements(VkDevice device, VkImage image, for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) if(memIdxMap[i] < 32U && (bits & (1U << memIdxMap[i]))) pMemoryRequirements->memoryTypeBits |= (1U << i); + + // AMD can have some variability in the returned size, so we need to pad the reported size to + // allow for this. The variability isn't quite clear, but for now we assume aligning size to + // alignment * 4 should be sufficient (adding on a fixed padding won't help the problem as it + // won't remove the variability, nor will adding then aligning for the same reason). + if(GetDriverVersion().IsAMD()) + { + VkMemoryRequirements &memreq = *pMemoryRequirements; + + VkDeviceSize oldsize = memreq.size; + memreq.size = AlignUp(memreq.size, memreq.alignment * 4); + + // if it's already 'super aligned', then bump it up a little. We assume that this case + // represents the low-end of the variation range, and other variations will be a little higher. + // The other alternative is the variations are all lower and this one happened to be super + // aligned, which I think (arbitrarily really) is less likely. + if(oldsize == memreq.size) + memreq.size = AlignUp(memreq.size + 1, memreq.alignment * 4); + + RDCDEBUG( + "Padded image memory requirements from %llu to %llu (base alignment %llu) (%f%% increase)", + oldsize, memreq.size, memreq.alignment, + (100.0 * double(memreq.size - oldsize)) / double(oldsize)); + } } void WrappedVulkan::vkGetImageSparseMemoryRequirements( @@ -218,6 +242,30 @@ void WrappedVulkan::vkGetImageMemoryRequirements2KHR(VkDevice device, for(uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) if(memIdxMap[i] < 32U && (bits & (1U << memIdxMap[i]))) pMemoryRequirements->memoryRequirements.memoryTypeBits |= (1U << i); + + // AMD can have some variability in the returned size, so we need to pad the reported size to + // allow for this. The variability isn't quite clear, but for now we assume aligning size to + // alignment * 4 should be sufficient (adding on a fixed padding won't help the problem as it + // won't remove the variability, nor will adding then aligning for the same reason). + if(GetDriverVersion().IsAMD()) + { + VkMemoryRequirements &memreq = pMemoryRequirements->memoryRequirements; + + VkDeviceSize oldsize = memreq.size; + memreq.size = AlignUp(memreq.size, memreq.alignment * 4); + + // if it's already 'super aligned', then bump it up a little. We assume that this case + // represents the low-end of the variation range, and other variations will be a little higher. + // The other alternative is the variations are all lower and this one happened to be super + // aligned, which I think (arbitrarily really) is less likely. + if(oldsize == memreq.size) + memreq.size = AlignUp(memreq.size + 1, memreq.alignment * 4); + + RDCDEBUG( + "Padded image memory requirements from %llu to %llu (base alignment %llu) (%f%% increase)", + oldsize, memreq.size, memreq.alignment, + (100.0 * double(memreq.size - oldsize)) / double(oldsize)); + } } void WrappedVulkan::vkGetImageSparseMemoryRequirements2KHR( diff --git a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp index 44749ff180..682b611450 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_misc_funcs.cpp @@ -497,7 +497,46 @@ bool WrappedVulkan::Serialise_vkCreateFramebuffer(Serialiser *localSerialiser, V live = GetResourceManager()->WrapResource(Unwrap(device), fb); GetResourceManager()->AddLiveResource(id, fb); - m_CreationInfo.m_Framebuffer[live].Init(GetResourceManager(), m_CreationInfo, &info); + VulkanCreationInfo::Framebuffer fbinfo; + fbinfo.Init(GetResourceManager(), m_CreationInfo, &info); + + const VulkanCreationInfo::RenderPass &rpinfo = + m_CreationInfo.m_RenderPass[GetResourceManager()->GetNonDispWrapper(info.renderPass)->id]; + + fbinfo.loadFBs.resize(rpinfo.loadRPs.size()); + + // create a render pass for each subpass that maintains attachment layouts + for(size_t s = 0; s < fbinfo.loadFBs.size(); s++) + { + info.renderPass = Unwrap(rpinfo.loadRPs[s]); + + ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), &info, NULL, &fbinfo.loadFBs[s]); + RDCASSERTEQUAL(ret, VK_SUCCESS); + + // handle the loadRP being a duplicate + if(GetResourceManager()->HasWrapper(ToTypedHandle(fbinfo.loadFBs[s]))) + { + // just fetch the existing wrapped object + fbinfo.loadFBs[s] = + (VkFramebuffer)(uint64_t)GetResourceManager()->GetNonDispWrapper(fbinfo.loadFBs[s]); + + // destroy this instance of the duplicate, as we must have matching create/destroy + // calls and there won't be a wrapped resource hanging around to destroy this one. + ObjDisp(device)->DestroyFramebuffer(Unwrap(device), fbinfo.loadFBs[s], NULL); + + // don't need to ReplaceResource as no IDs are involved + } + else + { + ResourceId loadFBid = + GetResourceManager()->WrapResource(Unwrap(device), fbinfo.loadFBs[s]); + + // register as a live-only resource, so it is cleaned up properly + GetResourceManager()->AddLiveResource(loadFBid, fbinfo.loadFBs[s]); + } + } + + m_CreationInfo.m_Framebuffer[live] = fbinfo; } } } @@ -567,7 +606,30 @@ VkResult WrappedVulkan::vkCreateFramebuffer(VkDevice device, { GetResourceManager()->AddLiveResource(id, *pFramebuffer); - m_CreationInfo.m_Framebuffer[id].Init(GetResourceManager(), m_CreationInfo, &unwrappedInfo); + VulkanCreationInfo::Framebuffer fbinfo; + fbinfo.Init(GetResourceManager(), m_CreationInfo, &unwrappedInfo); + + const VulkanCreationInfo::RenderPass &rpinfo = + m_CreationInfo.m_RenderPass[GetResID(pCreateInfo->renderPass)]; + + fbinfo.loadFBs.resize(rpinfo.loadRPs.size()); + + // create a render pass for each subpass that maintains attachment layouts + for(size_t s = 0; s < fbinfo.loadFBs.size(); s++) + { + unwrappedInfo.renderPass = Unwrap(rpinfo.loadRPs[s]); + + ret = ObjDisp(device)->CreateFramebuffer(Unwrap(device), &unwrappedInfo, NULL, + &fbinfo.loadFBs[s]); + RDCASSERTEQUAL(ret, VK_SUCCESS); + + ResourceId loadFBid = GetResourceManager()->WrapResource(Unwrap(device), fbinfo.loadFBs[s]); + + // register as a live-only resource, so it is cleaned up properly + GetResourceManager()->AddLiveResource(loadFBid, fbinfo.loadFBs[s]); + } + + m_CreationInfo.m_Framebuffer[id] = fbinfo; } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp index 89a83c6ff0..29e2baf1f0 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_queue_funcs.cpp @@ -228,11 +228,17 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(Serialiser *localSerialiser, VkQueue for(size_t e = 0; e < cmdBufInfo.draw->executedCmds.size(); e++) { - vector &submits = + vector &submits = m_Partial[Secondary].cmdBufferSubmits[cmdBufInfo.draw->executedCmds[e]]; for(size_t s = 0; s < submits.size(); s++) - submits[s] += m_RootEventID; + { + if(!submits[s].rebased) + { + submits[s].baseEvent += m_RootEventID; + submits[s].rebased = true; + } + } } for(size_t i = 0; i < cmdBufInfo.debugMessages.size(); i++) @@ -242,7 +248,7 @@ bool WrappedVulkan::Serialise_vkQueueSubmit(Serialiser *localSerialiser, VkQueue } // only primary command buffers can be submitted - m_Partial[Primary].cmdBufferSubmits[cmdIds[c]].push_back(m_RootEventID); + m_Partial[Primary].cmdBufferSubmits[cmdIds[c]].push_back(Submission(m_RootEventID)); m_RootEventID += cmdBufInfo.eventCount; m_RootDrawcallID += cmdBufInfo.drawCount; diff --git a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp index c31ab7bff9..5eac8d686a 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_resource_funcs.cpp @@ -501,7 +501,10 @@ void WrappedVulkan::vkFreeMemory(VkDevice device, VkDeviceMemory memory, { // there is an implicit unmap on free, so make sure to tidy up if(wrapped->record->memMapState && wrapped->record->memMapState->refData) + { Serialiser::FreeAlignedBuffer(wrapped->record->memMapState->refData); + wrapped->record->memMapState->refData = NULL; + } { SCOPED_LOCK(m_CoherentMapsLock); @@ -668,6 +671,7 @@ void WrappedVulkan::vkUnmapMemory(VkDevice device, VkDeviceMemory mem) } Serialiser::FreeAlignedBuffer(state.refData); + state.refData = NULL; if(state.mapCoherent) { @@ -731,7 +735,7 @@ bool WrappedVulkan::Serialise_vkFlushMappedMemoryRanges(Serialiser *localSeriali byte *serialisedData = localSerialiser->GetRawPtr(offs); - memcpy(state->refData, serialisedData + (size_t)memOffset, (size_t)memSize); + memcpy(state->refData, serialisedData, (size_t)memSize); } if(m_State < WRITING) diff --git a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp index e3aa7e8079..76a34b53c9 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_shader_funcs.cpp @@ -438,6 +438,20 @@ VkResult WrappedVulkan::vkCreateGraphicsPipelines(VkDevice device, VkPipelineCac VkResourceRecord *record = GetResourceManager()->AddResourceRecord(pPipelines[i]); record->AddChunk(chunk); + if(pCreateInfos[i].basePipelineHandle != VK_NULL_HANDLE) + { + VkResourceRecord *baserecord = GetRecord(pCreateInfos[i].basePipelineHandle); + record->AddParent(baserecord); + + RDCLOG("Creating pipeline %llu base is %llu", record->GetResourceID(), + baserecord->GetResourceID()); + } + else if(pCreateInfos[i].basePipelineIndex != -1 && pCreateInfos[i].basePipelineIndex < (int)i) + { + VkResourceRecord *baserecord = GetRecord(pPipelines[pCreateInfos[i].basePipelineIndex]); + record->AddParent(baserecord); + } + if(pipelineCache != VK_NULL_HANDLE) { VkResourceRecord *cacherecord = GetRecord(pipelineCache); @@ -553,9 +567,21 @@ VkResult WrappedVulkan::vkCreateComputePipelines(VkDevice device, VkPipelineCach { CACHE_THREAD_SERIALISER(); + VkComputePipelineCreateInfo modifiedCreateInfo; + const VkComputePipelineCreateInfo *createInfo = &pCreateInfos[i]; + + // since we serialise one by one, we need to fixup basePipelineIndex + if(createInfo->basePipelineIndex != -1 && createInfo->basePipelineIndex < (int)i) + { + modifiedCreateInfo = *createInfo; + modifiedCreateInfo.basePipelineHandle = pPipelines[modifiedCreateInfo.basePipelineIndex]; + modifiedCreateInfo.basePipelineIndex = -1; + createInfo = &modifiedCreateInfo; + } + SCOPED_SERIALISE_CONTEXT(CREATE_COMPUTE_PIPE); - Serialise_vkCreateComputePipelines(localSerialiser, device, pipelineCache, 1, - &pCreateInfos[i], NULL, &pPipelines[i]); + Serialise_vkCreateComputePipelines(localSerialiser, device, pipelineCache, 1, createInfo, + NULL, &pPipelines[i]); chunk = scope.Get(); } @@ -569,6 +595,17 @@ VkResult WrappedVulkan::vkCreateComputePipelines(VkDevice device, VkPipelineCach record->AddParent(cacherecord); } + if(pCreateInfos[i].basePipelineHandle != VK_NULL_HANDLE) + { + VkResourceRecord *baserecord = GetRecord(pCreateInfos[i].basePipelineHandle); + record->AddParent(baserecord); + } + else if(pCreateInfos[i].basePipelineIndex != -1 && pCreateInfos[i].basePipelineIndex < (int)i) + { + VkResourceRecord *baserecord = GetRecord(pPipelines[pCreateInfos[i].basePipelineIndex]); + record->AddParent(baserecord); + } + VkResourceRecord *layoutrecord = GetRecord(pCreateInfos[i].layout); record->AddParent(layoutrecord); diff --git a/renderdoc/os/posix/linux/linux_stringio.cpp b/renderdoc/os/posix/linux/linux_stringio.cpp index 0948bcbe29..37de5366e8 100644 --- a/renderdoc/os/posix/linux/linux_stringio.cpp +++ b/renderdoc/os/posix/linux/linux_stringio.cpp @@ -42,6 +42,7 @@ #endif #if ENABLED(RDOC_XCB) +#include #include #endif @@ -137,6 +138,10 @@ bool GetXlibKeyState(int key) // if RENDERDOC_WINDOWING_XLIB is not enabled +void CloneDisplay(Display *dpy) +{ +} + bool GetXlibKeyState(int key) { return false; @@ -160,7 +165,7 @@ bool GetXCBKeyState(int key) if(symbols == NULL) return false; - KeySym ks = 0; + xcb_keysym_t ks = 0; if(key >= eRENDERDOC_Key_A && key <= eRENDERDOC_Key_Z) ks = key; diff --git a/renderdoc/os/win32/win32_process.cpp b/renderdoc/os/win32/win32_process.cpp index 4d62434ba4..bd60c13637 100644 --- a/renderdoc/os/win32/win32_process.cpp +++ b/renderdoc/os/win32/win32_process.cpp @@ -307,7 +307,7 @@ uintptr_t FindRemoteDLL(DWORD pid, wstring libName) numModules++; - if(wcsstr(modnameLower, libName.c_str())) + if(wcsstr(modnameLower, libName.c_str()) == modnameLower) { ret = (uintptr_t)me32.modBaseAddr; } @@ -326,7 +326,7 @@ uintptr_t FindRemoteDLL(DWORD pid, wstring libName) { RDCERR( "Error injecting into remote process with PID %u which is no longer available.\n" - "Possibly the process has crashed during early startup?", + "Possibly the process has crashed during early startup, or is missing DLLs to run?", pid); } else diff --git a/renderdoc/replay/replay_output.cpp b/renderdoc/replay/replay_output.cpp index 32ebad8825..1b18351937 100644 --- a/renderdoc/replay/replay_output.cpp +++ b/renderdoc/replay/replay_output.cpp @@ -119,7 +119,8 @@ ReplayOutput::~ReplayOutput() void ReplayOutput::SetTextureDisplay(const TextureDisplay &o) { - if(o.overlay != m_RenderData.texDisplay.overlay) + if(o.overlay != m_RenderData.texDisplay.overlay || + o.typeHint != m_RenderData.texDisplay.typeHint || o.texid != m_RenderData.texDisplay.texid) { if(m_RenderData.texDisplay.overlay == DebugOverlay::ClearBeforeDraw || m_RenderData.texDisplay.overlay == DebugOverlay::ClearBeforePass) diff --git a/renderdoccmd/CMakeLists.txt b/renderdoccmd/CMakeLists.txt index c748dccd53..0b44b442c3 100644 --- a/renderdoccmd/CMakeLists.txt +++ b/renderdoccmd/CMakeLists.txt @@ -57,23 +57,56 @@ target_link_libraries(renderdoccmd ${libraries}) install (TARGETS renderdoccmd DESTINATION bin) if(ANDROID) + if(NOT DEFINED ENV{JAVA_HOME}) + message(FATAL_ERROR "JAVA_HOME environment variable must be defined for Android build") + endif() + if(NOT DEFINED ENV{ANDROID_SDK}) + message(FATAL_ERROR "ANDROID_SDK environment variable must be defined for Android build") + endif() + + set(ANDROID_BUILD_TOOLS_VERSION "" CACHE STRING "Version of Android build-tools to use instead of the default") + if(ANDROID_BUILD_TOOLS_VERSION STREQUAL "") + set(ANDROID_BUILD_TOOLS_VERSION "26.0.1") + endif() + message(STATUS "Using Android build-tools version ${ANDROID_BUILD_TOOLS_VERSION}") + + set(BUILD_TOOLS "$ENV{ANDROID_SDK}/build-tools/${ANDROID_BUILD_TOOLS_VERSION}") + set(RT_JAR "$ENV{JAVA_HOME}/jre/lib/rt.jar") + set(JAVA_BIN "$ENV{JAVA_HOME}/bin") + set(APK_TARGET_ID "android-23" CACHE STRING "The Target ID to build the APK for, use to choose another one.") + set(ANDROID_JAR "$ENV{ANDROID_SDK}/platforms/${APK_TARGET_ID}/android.jar") + if(CMAKE_HOST_WIN32) + set(CLASS_PATH "${ANDROID_JAR}\;obj") + else() + set(CLASS_PATH "${ANDROID_JAR}:obj") + endif() + set(KEYSTORE ${CMAKE_CURRENT_BINARY_DIR}/debug.keystore) + add_custom_command(OUTPUT ${KEYSTORE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${JAVA_BIN}/keytool -genkey -keystore ${KEYSTORE} -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "CN=, OU=, O=, L=, S=, C=") set(APK_FILE ${CMAKE_BINARY_DIR}/bin/RenderDocCmd.apk) add_custom_target(apk ALL - DEPENDS ${APK_FILE}) + DEPENDS ${APK_FILE} + DEPENDS ${KEYSTORE}) + add_custom_command(OUTPUT ${APK_FILE} DEPENDS renderdoc DEPENDS renderdoccmd WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/android ${CMAKE_CURRENT_BINARY_DIR} - COMMAND ${CMAKE_COMMAND} -E make_directory libs/${ANDROID_ABI} - COMMAND ${CMAKE_COMMAND} -E copy $ libs/${ANDROID_ABI}/libVkLayer_GLES_RenderDoc.so - COMMAND ${CMAKE_COMMAND} -E copy $ libs/${ANDROID_ABI}/$ - COMMAND android update project --path . --name RenderDocCmd --target ${APK_TARGET_ID} - COMMAND ant debug - COMMAND ${CMAKE_COMMAND} -E copy bin/RenderDocCmd-debug.apk ${APK_FILE} - COMMAND ${CMAKE_COMMAND} -E make_directory libs/lib - COMMAND ${CMAKE_COMMAND} -E copy_directory libs/${ANDROID_ABI} libs/lib/${ANDROID_ABI} - COMMAND ${CMAKE_COMMAND} -E remove_directory libs/${ANDROID_ABI}) + COMMAND ${CMAKE_COMMAND} -E make_directory libs/lib/${ANDROID_ABI} + COMMAND ${CMAKE_COMMAND} -E make_directory obj + COMMAND ${CMAKE_COMMAND} -E make_directory bin + COMMAND ${CMAKE_COMMAND} -E copy $ libs/lib/${ANDROID_ABI}/libVkLayer_GLES_RenderDoc.so + COMMAND ${CMAKE_COMMAND} -E copy $ libs/lib/${ANDROID_ABI}/$ + COMMAND ${BUILD_TOOLS}/aapt package -f -m -S res -J src -M AndroidManifest.xml -I ${ANDROID_JAR} + COMMAND ${JAVA_BIN}/javac -d ./obj -source 1.7 -target 1.7 -bootclasspath ${RT_JAR} -classpath "${CLASS_PATH}" -sourcepath src src/org/renderdoc/renderdoccmd/*.java + COMMAND ${BUILD_TOOLS}/dx --dex --output=bin/classes.dex ./obj + COMMAND ${BUILD_TOOLS}/aapt package -f -M AndroidManifest.xml -S res -I ${ANDROID_JAR} -F RenderDocCmd-unaligned.apk bin libs + COMMAND ${BUILD_TOOLS}/zipalign -f 4 RenderDocCmd-unaligned.apk RenderDocCmd.apk + COMMAND ${BUILD_TOOLS}/apksigner sign --ks ${KEYSTORE} --ks-pass pass:android --key-pass pass:android --ks-key-alias androiddebugkey RenderDocCmd.apk + COMMAND ${CMAKE_COMMAND} -E copy RenderDocCmd.apk ${APK_FILE}) + endif() diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp index d3727bb8e1..9d29bbcc10 100644 --- a/renderdoccmd/renderdoccmd.cpp +++ b/renderdoccmd/renderdoccmd.cpp @@ -270,6 +270,8 @@ struct ThumbCommand : public Command type = FileType::TGA; else if(dot != NULL && strstr(dot, "bmp")) type = FileType::BMP; + else if(dot != NULL && strstr(dot, "jpg")) + type = FileType::JPG; else std::cerr << "Couldn't guess format from '" << outfile << "', defaulting to jpg." << std::endl; diff --git a/renderdoccmd/renderdoccmd_linux.cpp b/renderdoccmd/renderdoccmd_linux.cpp index 99a129ccf5..48e5e7b5a3 100644 --- a/renderdoccmd/renderdoccmd_linux.cpp +++ b/renderdoccmd/renderdoccmd_linux.cpp @@ -372,11 +372,13 @@ int main(int argc, char *argv[]) GlobalEnvironment env; +#if defined(RENDERDOC_WINDOWING_XLIB) || defined(RENDERDOC_WINDOWING_XCB) // call XInitThreads - although we don't use xlib concurrently the driver might need to. XInitThreads(); // we don't check if display successfully opened, it's only a problem if it's needed later. display = env.xlibDisplay = XOpenDisplay(NULL); +#endif #if defined(RENDERDOC_SUPPORT_VULKAN) VerifyVulkanLayer(env, argc, argv); diff --git a/renderdocui/Properties/AssemblyInfo.cs b/renderdocui/Properties/AssemblyInfo.cs index 0020a9d4c8..fbc36ed586 100644 --- a/renderdocui/Properties/AssemblyInfo.cs +++ b/renderdocui/Properties/AssemblyInfo.cs @@ -59,8 +59,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.35.0.0")] -[assembly: AssemblyFileVersion("0.35.0.0")] +[assembly: AssemblyVersion("0.91.0.0")] +[assembly: AssemblyFileVersion("0.91.0.0")] // this can be replaced with the git hash of the commit being built from e.g. in a script [assembly: AssemblyInformationalVersion("NO_GIT_COMMIT_HASH_DEFINED")] diff --git a/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs b/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs index cc90e87089..5bc57232a0 100644 --- a/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs +++ b/renderdocui/Windows/PipelineState/VulkanPipelineStateViewer.cs @@ -381,6 +381,26 @@ private void AddResourceRow(ShaderReflection shaderDetails, VulkanPipelineState. if (shaderDetails != null) { + // we find the matching binding for this set/binding. + // The spec requires that there are no overlapping definitions, or if there are they have + // compatible types so we can just pick the first one we come across. + // The spec also doesn't require variables which are statically unused to have valid bindings, + // so they may be overlapping or possibly just defaulted to 0. + // Any variables with no binding declared at all were set to 0 and sorted to the end at + // reflection time, so we can just use a single algorithm to select the best candidate: + // + // 1. Search for matching bindset/bind resources. It doesn't matter which 'namespace' (sampler/ + // read-only/read-write) we search in, because if there's a conflict the behaviour is + // illegal and if there's no conflict we won't get any ambiguity. + // 2. If we find a match, select it for use. + // 3. If we find a second match, use it in preference only if the old one was !used, and the new + // one is used. + // + // This will make us select the best possible option - the first declared used resource + // at a particular binding, ignoring any unused resources at that binding before/after. Or if + // there's no used resource at all, the first declared unused resource (which will prefer + // resources with proper bindings over those without, as with the sorting mentioned above). + for (int i = 0; i < shaderDetails.ReadOnlyResources.Length; i++) { var ro = shaderDetails.ReadOnlyResources[i]; @@ -388,9 +408,12 @@ private void AddResourceRow(ShaderReflection shaderDetails, VulkanPipelineState. if (stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bindset == bindset && stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].bind == bind) { - bindPoint = (uint)i; - shaderRes = ro; - bindMap = stage.BindpointMapping.ReadOnlyResources[ro.bindPoint]; + if (bindMap == null || (!bindMap.used && stage.BindpointMapping.ReadOnlyResources[ro.bindPoint].used)) + { + bindPoint = (uint)i; + shaderRes = ro; + bindMap = stage.BindpointMapping.ReadOnlyResources[ro.bindPoint]; + } } } @@ -401,10 +424,13 @@ private void AddResourceRow(ShaderReflection shaderDetails, VulkanPipelineState. if (stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bindset == bindset && stage.BindpointMapping.ReadWriteResources[rw.bindPoint].bind == bind) { - bindPoint = (uint)i; - isrw = true; - shaderRes = rw; - bindMap = stage.BindpointMapping.ReadWriteResources[rw.bindPoint]; + if (bindMap == null || (!bindMap.used && stage.BindpointMapping.ReadWriteResources[rw.bindPoint].used)) + { + bindPoint = (uint)i; + isrw = true; + shaderRes = rw; + bindMap = stage.BindpointMapping.ReadWriteResources[rw.bindPoint]; + } } } } diff --git a/renderdocui/Windows/ShaderViewer.cs b/renderdocui/Windows/ShaderViewer.cs index 5f63cbb33f..7a85bd5042 100644 --- a/renderdocui/Windows/ShaderViewer.cs +++ b/renderdocui/Windows/ShaderViewer.cs @@ -490,12 +490,7 @@ public ShaderViewer(Core core, ShaderReflection shader, ShaderStageType stage, S disasmToolStrip.Items.AddRange(new ToolStripItem[] { disasmTypeLabel, disasmType }); disasmToolStrip.Margin = new Padding(0, 0, 12, 0); - disasmLayoutPanel.ColumnCount = 1; - disasmLayoutPanel.Controls.Add(disasmToolStrip, 0, 0); - disasmLayoutPanel.Controls.Add(m_DisassemblyView, 0, 1); - disasmLayoutPanel.RowCount = 2; - disasmLayoutPanel.RowStyles.Add(new RowStyle()); - disasmLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F)); + disasmLayoutPanel.Dock = DockStyle.Fill; if (m_Trace == null) { @@ -580,9 +575,10 @@ public ShaderViewer(Core core, ShaderReflection shader, ShaderStageType stage, S AddFileList(); if (trace != null || sel == null) - sel = (DockContent)m_DisassemblyView.Parent; + sel = DockContentFor(m_DisassemblyView); - sel.Show(); + if(sel != null) + sel.Show(); } ShowConstants(); @@ -705,7 +701,11 @@ void list_SelectedIndexChanged(object sender, EventArgs e) int idx = m_FileList.SelectedIndex; if (idx >= 0 && idx < m_Scintillas.Count) - (m_Scintillas[idx].Parent as DockContent).Show(); + { + DockContent dock = DockContentFor(m_Scintillas[idx]); + if (dock != null) + dock.Show(); + } } private void AddFileList() @@ -720,7 +720,11 @@ private void AddFileList() m_FileList.SelectedIndexChanged += new EventHandler(list_SelectedIndexChanged); foreach (ScintillaNET.Scintilla s in m_Scintillas) - m_FileList.Items.Add((s.Parent as DockContent).Text); + { + DockContent dock = DockContentFor(s); + if(dock != null) + m_FileList.Items.Add(dock.Text); + } var w = Helpers.WrapDockContent(dockPanel, m_FileList, "File List"); w.DockState = DockState.DockLeft; @@ -832,7 +836,11 @@ void FindAllFiles() w.DockAreas |= DockAreas.Float; w.DockState = DockState.DockBottom; w.HideOnClose = true; - w.Show((m_Scintillas[0].Parent as DockContent).Pane, DockAlignment.Bottom, 0.5); + DockContent dock = DockContentFor(m_Scintillas[0]); + if(dock != null) + w.Show(dock.Pane, DockAlignment.Bottom, 0.5); + else + w.Show(); } else { @@ -879,7 +887,11 @@ void FindAllFiles() foreach (var kv in findResultsByEd) { - string filename = (kv.Key.Parent as DockContent).Text; + DockContent dock = DockContentFor(kv.Key); + if (dock == null) + continue; + + string filename = dock.Text; if (kv.Value.Count > 0) fileCount++; @@ -928,10 +940,13 @@ void findResults_DoubleClick(object sender, EventArgs e) int idx = line - 1; - DockContent dc = (m_FindResults[idx].Key.Parent as DockContent); + DockContent dc = DockContentFor(m_FindResults[idx].Key); - dc.Activate(); - dc.Show(); + if (dc != null) + { + dc.Activate(); + dc.Show(); + } m_FindResults[idx].Key.GoTo.Line(m_FindResults[idx].Value.StartingLine.Number); @@ -2384,5 +2399,20 @@ private void findinall_Click(object sender, EventArgs e) { ShowFindAll(); } + + private DockContent DockContentFor(Control c) + { + Control p = c.Parent; + while (p != null) + { + if (p is DockContent) + return (DockContent)p; + + p = p.Parent; + } + + return null; + } + } } \ No newline at end of file diff --git a/scripts/travis/android_setup.sh b/scripts/travis/android_setup.sh index a884b82568..aa49545366 100644 --- a/scripts/travis/android_setup.sh +++ b/scripts/travis/android_setup.sh @@ -6,27 +6,17 @@ sudo apt-get install -y cmake export ARCH=`uname -m` -# Pull known working tools toward the end of 2016 -wget http://dl.google.com/android/repository/android-ndk-r13b-linux-${ARCH}.zip -wget https://dl.google.com/android/repository/tools_r25.2.5-linux.zip -wget https://dl.google.com/android/repository/platform-tools_r25.0.3-linux.zip -wget https://dl.google.com/android/repository/build-tools_r25.0.2-linux.zip -unzip -u -q android-ndk-r13b-linux-${ARCH}.zip -unzip -u -q tools_r25.2.5-linux.zip -unzip -u -q platform-tools_r25.0.3-linux.zip -unzip -u -q build-tools_r25.0.2-linux.zip +# Pull known working tools August 2017 +wget http://dl.google.com/android/repository/sdk-tools-linux-3859397.zip +wget http://dl.google.com/android/repository/android-ndk-r14b-linux-${ARCH}.zip +unzip -u -q android-ndk-r14b-linux-${ARCH}.zip +unzip -u -q sdk-tools-linux-3859397.zip -# Munge the build-tools layout -mkdir -p build-tools/25.0.2 -mv android-7.1.1/* build-tools/25.0.2/ - -export ANDROID_HOME=`pwd`/tools export JAVA_HOME="/usr/lib/jvm/java-8-oracle" -export ANDROID_NDK=`pwd`/android-ndk-r13b -export PATH=`pwd`/android-ndk-r13b:$PATH -export PATH=`pwd`/tools:$PATH -export PATH=`pwd`/platform-tools:$PATH -export PATH=`pwd`/build-tools/25.0.2:$PATH +export ANDROID_NDK=$TRAVIS_BUILD_DIR/android-ndk-r14b +export ANDROID_SDK=$TRAVIS_BUILD_DIR # Answer "yes" to any license acceptance requests -(while sleep 3; do echo "y"; done) | android update sdk --no-ui -s -t android-23 +pushd tools/bin +(while sleep 3; do echo "y"; done) | ./sdkmanager --sdk_root=$TRAVIS_BUILD_DIR "build-tools;26.0.1" "platforms;android-23" +popd diff --git a/scripts/travis/docs_setup.sh b/scripts/travis/docs_setup.sh index d766b5520c..ca38ad8e0a 100644 --- a/scripts/travis/docs_setup.sh +++ b/scripts/travis/docs_setup.sh @@ -1,5 +1,5 @@ #!/bin/sh set -ev -pip install --upgrade pip setuptools -pip install Sphinx sphinx-rtd-theme +sudo pip install --upgrade pip setuptools +sudo pip install Sphinx sphinx-rtd-theme diff --git a/scripts/travis/osx_setup.sh b/scripts/travis/osx_setup.sh index 07cf25668b..b8a1278808 100644 --- a/scripts/travis/osx_setup.sh +++ b/scripts/travis/osx_setup.sh @@ -1,5 +1,6 @@ #!/bin/sh +brew update brew install qt5 brew link qt5 --force brew install python3