OpenGL: Use non-filtering samplers for int/uint texture.

Using a sampler with filtering on int / uint textures makes them
incomplete, causing them to sample black on very conformant drivers.
Each opengl::Sampler is updated to create to GL sampler, a filtering one
and a non-filtering one.

PipelineGL and CommandBufferGL takes advantage of the new
BGLBinding::textureComponentType to know which of the two samplers to
use.

BUG=dawn:128

Change-Id: Idbf5668213bbe6a8639847d57e2be1244f97800c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/10282
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez
2019-08-21 13:01:23 +00:00
committed by Commit Bot service account
parent f463a20291
commit ba9f3a8e11
6 changed files with 80 additions and 80 deletions

View File

@@ -246,12 +246,18 @@ namespace dawn_native { namespace opengl {
} break;
case dawn::BindingType::Sampler: {
GLuint sampler =
ToBackend(group->GetBindingAsSampler(bindingIndex))->GetHandle();
Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
GLuint samplerIndex = indices[bindingIndex];
for (auto unit : pipeline->GetTextureUnitsForSampler(samplerIndex)) {
gl.BindSampler(unit, sampler);
for (PipelineGL::SamplerUnit unit :
pipeline->GetTextureUnitsForSampler(samplerIndex)) {
// Only use filtering for certain texture units, because int and uint
// texture are only complete without filtering
if (unit.shouldUseFiltering) {
gl.BindSampler(unit.unit, sampler->GetFilteringHandle());
} else {
gl.BindSampler(unit.unit, sampler->GetNonFilteringHandle());
}
}
} break;

View File

@@ -173,20 +173,27 @@ namespace dawn_native { namespace opengl {
gl.Uniform1i(location, textureUnit);
GLuint samplerIndex =
indices[combined.samplerLocation.group][combined.samplerLocation.binding];
mUnitsForSamplers[samplerIndex].push_back(textureUnit);
GLuint textureIndex =
indices[combined.textureLocation.group][combined.textureLocation.binding];
mUnitsForTextures[textureIndex].push_back(textureUnit);
dawn::TextureComponentType componentType =
layout->GetBindGroupLayout(combined.textureLocation.group)
->GetBindingInfo()
.textureComponentTypes[combined.textureLocation.binding];
bool shouldUseFiltering = componentType == dawn::TextureComponentType::Float;
GLuint samplerIndex =
indices[combined.samplerLocation.group][combined.samplerLocation.binding];
mUnitsForSamplers[samplerIndex].push_back({textureUnit, shouldUseFiltering});
textureUnit++;
}
}
}
const std::vector<GLuint>& PipelineGL::GetTextureUnitsForSampler(GLuint index) const {
const std::vector<PipelineGL::SamplerUnit>& PipelineGL::GetTextureUnitsForSampler(
GLuint index) const {
ASSERT(index < mUnitsForSamplers.size());
return mUnitsForSamplers[index];
}

View File

@@ -39,7 +39,13 @@ namespace dawn_native { namespace opengl {
using BindingLocations =
std::array<std::array<GLint, kMaxBindingsPerGroup>, kMaxBindGroups>;
const std::vector<GLuint>& GetTextureUnitsForSampler(GLuint index) const;
// For each unit a sampler is bound to we need to know if we should use filtering or not
// because int and uint texture are only complete without filtering.
struct SamplerUnit {
GLuint unit;
bool shouldUseFiltering;
};
const std::vector<SamplerUnit>& GetTextureUnitsForSampler(GLuint index) const;
const std::vector<GLuint>& GetTextureUnitsForTextureView(GLuint index) const;
GLuint GetProgramHandle() const;
@@ -47,7 +53,7 @@ namespace dawn_native { namespace opengl {
private:
GLuint mProgram;
std::vector<std::vector<GLuint>> mUnitsForSamplers;
std::vector<std::vector<SamplerUnit>> mUnitsForSamplers;
std::vector<std::vector<GLuint>> mUnitsForTextures;
};

View File

@@ -76,26 +76,53 @@ namespace dawn_native { namespace opengl {
: SamplerBase(device, descriptor) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.GenSamplers(1, &mHandle);
gl.SamplerParameteri(mHandle, GL_TEXTURE_MAG_FILTER, MagFilterMode(descriptor->magFilter));
gl.SamplerParameteri(mHandle, GL_TEXTURE_MIN_FILTER,
MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter));
gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW));
gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU));
gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV));
gl.GenSamplers(1, &mFilteringHandle);
SetupGLSampler(mFilteringHandle, descriptor, false);
gl.SamplerParameterf(mHandle, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp);
gl.SamplerParameterf(mHandle, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp);
gl.GenSamplers(1, &mNonFilteringHandle);
SetupGLSampler(mNonFilteringHandle, descriptor, true);
}
Sampler::~Sampler() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
gl.DeleteSamplers(1, &mFilteringHandle);
gl.DeleteSamplers(1, &mNonFilteringHandle);
}
void Sampler::SetupGLSampler(GLuint sampler,
const SamplerDescriptor* descriptor,
bool forceNearest) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
if (forceNearest) {
gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
} else {
gl.SamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER,
MagFilterMode(descriptor->magFilter));
gl.SamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER,
MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter));
}
gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW));
gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU));
gl.SamplerParameteri(sampler, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV));
gl.SamplerParameterf(sampler, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp);
gl.SamplerParameterf(sampler, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp);
if (ToOpenGLCompareFunction(descriptor->compare) != GL_NEVER) {
gl.SamplerParameteri(mHandle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
gl.SamplerParameteri(mHandle, GL_TEXTURE_COMPARE_FUNC,
gl.SamplerParameteri(sampler, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
gl.SamplerParameteri(sampler, GL_TEXTURE_COMPARE_FUNC,
ToOpenGLCompareFunction(descriptor->compare));
}
}
GLuint Sampler::GetHandle() const {
return mHandle;
GLuint Sampler::GetFilteringHandle() const {
return mFilteringHandle;
}
GLuint Sampler::GetNonFilteringHandle() const {
return mNonFilteringHandle;
}
}} // namespace dawn_native::opengl

View File

@@ -26,11 +26,19 @@ namespace dawn_native { namespace opengl {
class Sampler : public SamplerBase {
public:
Sampler(Device* device, const SamplerDescriptor* descriptor);
~Sampler();
GLuint GetHandle() const;
GLuint GetFilteringHandle() const;
GLuint GetNonFilteringHandle() const;
private:
GLuint mHandle;
void SetupGLSampler(GLuint sampler, const SamplerDescriptor* descriptor, bool forceNearest);
GLuint mFilteringHandle;
// This is a sampler equivalent to mFilteringHandle except that it uses NEAREST filtering
// for everything, which is important to preserve texture completeness for u/int textures.
GLuint mNonFilteringHandle;
};
}} // namespace dawn_native::opengl