Pass texture base level to shaders on D3D11
The base level is passed to shaders in a uniform block created
specifically for passing sampler metadata. This is done on feature levels
above 9_3, which treat samplers as indices to sampler arrays in shaders.
BUG=angleproject:596
TEST=angle_end2end_tests
Change-Id: I846f2fc195ab1fd884052824ffd3c1d65083c0fb
Reviewed-on: https://chromium-review.googlesource.com/322122
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index bde3409..bb10266 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -22,6 +22,7 @@
#include "libANGLE/renderer/d3d/ShaderExecutableD3D.h"
#include "libANGLE/renderer/d3d/VaryingPacking.h"
#include "libANGLE/renderer/d3d/VertexDataManager.h"
+#include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
@@ -487,6 +488,88 @@
return mFragmentShader;
}
+// SamplerMetadataD3D11 implementation
+
+SamplerMetadataD3D11::SamplerMetadataD3D11()
+ : mSamplerCount(0), mType(gl::SAMPLER_VERTEX), mDirty(false), mSamplerMetadataBuffer(nullptr)
+{
+}
+
+SamplerMetadataD3D11::~SamplerMetadataD3D11()
+{
+ reset();
+}
+
+void SamplerMetadataD3D11::reset()
+{
+ mDirty = false;
+ SafeRelease(mSamplerMetadataBuffer);
+}
+
+void SamplerMetadataD3D11::initData(unsigned int samplerCount, gl::SamplerType type)
+{
+ mSamplerMetadata.resize(samplerCount);
+ mSamplerCount = samplerCount;
+ mType = type;
+}
+
+void SamplerMetadataD3D11::update(unsigned int samplerIndex, unsigned int baseLevel)
+{
+ if (mSamplerMetadata[samplerIndex].baseLevel[0] != static_cast<int>(baseLevel))
+ {
+ mSamplerMetadata[samplerIndex].baseLevel[0] = static_cast<int>(baseLevel);
+ mDirty = true;
+ }
+}
+
+bool SamplerMetadataD3D11::initBuffer(ID3D11Device *device, ID3D11DeviceContext *deviceContext)
+{
+ D3D11_BUFFER_DESC constantBufferDescription = {0};
+ d3d11::InitConstantBufferDesc(&constantBufferDescription,
+ sizeof(dx_SamplerMetadata) * mSamplerCount);
+ HRESULT result =
+ device->CreateBuffer(&constantBufferDescription, nullptr, &mSamplerMetadataBuffer);
+ ASSERT(SUCCEEDED(result));
+ if (FAILED(result))
+ {
+ return false;
+ }
+ if (mType == gl::SAMPLER_VERTEX)
+ {
+ deviceContext->VSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_SAMPLER_METADATA,
+ 1, &mSamplerMetadataBuffer);
+ }
+ else
+ {
+ deviceContext->PSSetConstantBuffers(d3d11::RESERVED_CONSTANT_BUFFER_SLOT_SAMPLER_METADATA,
+ 1, &mSamplerMetadataBuffer);
+ }
+ mDirty = true;
+ return true;
+}
+
+gl::Error SamplerMetadataD3D11::apply(ID3D11Device *device, ID3D11DeviceContext *deviceContext)
+{
+ if (!mSamplerMetadataBuffer && mSamplerCount > 0)
+ {
+ if (!initBuffer(device, deviceContext))
+ {
+ return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader constant buffer");
+ }
+ }
+ if (mDirty)
+ {
+ ASSERT(mSamplerMetadataBuffer);
+ if (mSamplerMetadataBuffer)
+ {
+ deviceContext->UpdateSubresource(mSamplerMetadataBuffer, 0, nullptr,
+ mSamplerMetadata.data(), 16, 0);
+ mDirty = false;
+ }
+ }
+ return gl::Error(GL_NO_ERROR);
+}
+
// ProgramD3D Implementation
ProgramD3D::VertexExecutable::VertexExecutable(const gl::InputLayout &inputLayout,
@@ -654,7 +737,29 @@
return GL_TEXTURE_2D;
}
-GLint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const
+void ProgramD3D::setSamplerMetadata(gl::SamplerType type,
+ unsigned int samplerIndex,
+ unsigned int baseLevel)
+{
+ SamplerMetadataD3D11 *metadata = nullptr;
+ switch (type)
+ {
+ case gl::SAMPLER_PIXEL:
+ metadata = &mSamplerMetadataPS;
+ break;
+ case gl::SAMPLER_VERTEX:
+ metadata = &mSamplerMetadataVS;
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ ASSERT(metadata != nullptr);
+ ASSERT(samplerIndex < getUsedSamplerRange(type));
+ metadata->update(samplerIndex, baseLevel);
+}
+
+GLuint ProgramD3D::getUsedSamplerRange(gl::SamplerType type) const
{
switch (type)
{
@@ -664,7 +769,7 @@
return mUsedVertexSamplerRange;
default:
UNREACHABLE();
- return 0;
+ return 0u;
}
}
@@ -958,6 +1063,9 @@
initializeUniformStorage();
initAttributesByLayout();
+ mSamplerMetadataPS.initData(getUsedSamplerRange(gl::SAMPLER_PIXEL), gl::SAMPLER_PIXEL);
+ mSamplerMetadataVS.initData(getUsedSamplerRange(gl::SAMPLER_VERTEX), gl::SAMPLER_VERTEX);
+
return LinkResult(true, gl::Error(GL_NO_ERROR));
}
@@ -1440,6 +1548,9 @@
defineUniformsAndAssignRegisters();
+ mSamplerMetadataPS.initData(getUsedSamplerRange(gl::SAMPLER_PIXEL), gl::SAMPLER_PIXEL);
+ mSamplerMetadataVS.initData(getUsedSamplerRange(gl::SAMPLER_VERTEX), gl::SAMPLER_VERTEX);
+
gatherTransformFeedbackVaryings(varyingPacking);
LinkResult result = compileProgramExecutables(data, infoLog);
@@ -1564,6 +1675,11 @@
d3dUniform->dirty = false;
}
+ error = mRenderer->applySamplerMetadata(&mSamplerMetadataVS, mUsedVertexSamplerRange,
+ gl::SAMPLER_VERTEX);
+ error = mRenderer->applySamplerMetadata(&mSamplerMetadataPS, mUsedPixelSamplerRange,
+ gl::SAMPLER_PIXEL);
+
return gl::Error(GL_NO_ERROR);
}
@@ -2140,6 +2256,9 @@
mSamplersPS.clear();
mSamplersVS.clear();
+ mSamplerMetadataPS.reset();
+ mSamplerMetadataVS.reset();
+
mUsedVertexSamplerRange = 0;
mUsedPixelSamplerRange = 0;
mDirtySamplerMapping = true;