Add Toggles to disable base vertex and base instance rendering
These are not supported on some older OpenGL, OpenGL ES, and iOS
devices.
Bug: dawn:343
Change-Id: I70def749ae57fcfe2895f8556674dd241941d3d3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16163
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/RenderEncoderBase.cpp b/src/dawn_native/RenderEncoderBase.cpp
index 0652d1f..532c448 100644
--- a/src/dawn_native/RenderEncoderBase.cpp
+++ b/src/dawn_native/RenderEncoderBase.cpp
@@ -27,13 +27,17 @@
namespace dawn_native {
RenderEncoderBase::RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext)
- : ProgrammablePassEncoder(device, encodingContext) {
+ : ProgrammablePassEncoder(device, encodingContext),
+ mDisableBaseVertex(device->IsToggleEnabled(Toggle::DisableBaseVertex)),
+ mDisableBaseInstance(device->IsToggleEnabled(Toggle::DisableBaseInstance)) {
}
RenderEncoderBase::RenderEncoderBase(DeviceBase* device,
EncodingContext* encodingContext,
ErrorTag errorTag)
- : ProgrammablePassEncoder(device, encodingContext, errorTag) {
+ : ProgrammablePassEncoder(device, encodingContext, errorTag),
+ mDisableBaseVertex(device->IsToggleEnabled(Toggle::DisableBaseVertex)),
+ mDisableBaseInstance(device->IsToggleEnabled(Toggle::DisableBaseInstance)) {
}
void RenderEncoderBase::Draw(uint32_t vertexCount,
@@ -41,6 +45,10 @@
uint32_t firstVertex,
uint32_t firstInstance) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
+ if (mDisableBaseInstance && firstInstance != 0) {
+ return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
+ }
+
DrawCmd* draw = allocator->Allocate<DrawCmd>(Command::Draw);
draw->vertexCount = vertexCount;
draw->instanceCount = instanceCount;
@@ -57,6 +65,13 @@
int32_t baseVertex,
uint32_t firstInstance) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
+ if (mDisableBaseInstance && firstInstance != 0) {
+ return DAWN_VALIDATION_ERROR("Non-zero first instance not supported");
+ }
+ if (mDisableBaseInstance && baseVertex != 0) {
+ return DAWN_VALIDATION_ERROR("Non-zero base vertex not supported");
+ }
+
DrawIndexedCmd* draw = allocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed);
draw->indexCount = indexCount;
draw->instanceCount = instanceCount;
diff --git a/src/dawn_native/RenderEncoderBase.h b/src/dawn_native/RenderEncoderBase.h
index 906c9e0..33343ae 100644
--- a/src/dawn_native/RenderEncoderBase.h
+++ b/src/dawn_native/RenderEncoderBase.h
@@ -45,6 +45,10 @@
protected:
// Construct an "error" render encoder base.
RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext, ErrorTag errorTag);
+
+ private:
+ const bool mDisableBaseVertex;
+ const bool mDisableBaseInstance;
};
} // namespace dawn_native
diff --git a/src/dawn_native/Toggles.cpp b/src/dawn_native/Toggles.cpp
index 578d52d..4e002d2 100644
--- a/src/dawn_native/Toggles.cpp
+++ b/src/dawn_native/Toggles.cpp
@@ -106,6 +106,13 @@
{"metal_disable_sampler_compare",
"Disables the use of sampler compare on Metal. This is unsupported before A9 "
"processors."}},
+ {Toggle::DisableBaseVertex,
+ {"disable_base_vertex",
+ "Disables the use of non-zero base vertex which is unsupported on some platforms."}},
+ {Toggle::DisableBaseInstance,
+ {"disable_base_instance",
+ "Disables the use of non-zero base instance which is unsupported on some "
+ "platforms."}},
}};
} // anonymous namespace
diff --git a/src/dawn_native/Toggles.h b/src/dawn_native/Toggles.h
index 3891f98..c9d7352 100644
--- a/src/dawn_native/Toggles.h
+++ b/src/dawn_native/Toggles.h
@@ -37,6 +37,8 @@
UseSpvcParser,
VulkanUseD32S8,
MetalDisableSamplerCompare,
+ DisableBaseVertex,
+ DisableBaseInstance,
EnumCount,
InvalidEnum = EnumCount,
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index 667404d..628f77b 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -1018,11 +1018,19 @@
// The instance count must be non-zero, otherwise no-op
if (draw->instanceCount != 0) {
- [encoder drawPrimitives:lastPipeline->GetMTLPrimitiveTopology()
- vertexStart:draw->firstVertex
- vertexCount:draw->vertexCount
- instanceCount:draw->instanceCount
- baseInstance:draw->firstInstance];
+ // MTLFeatureSet_iOS_GPUFamily3_v1 does not support baseInstance
+ if (draw->firstInstance == 0) {
+ [encoder drawPrimitives:lastPipeline->GetMTLPrimitiveTopology()
+ vertexStart:draw->firstVertex
+ vertexCount:draw->vertexCount
+ instanceCount:draw->instanceCount];
+ } else {
+ [encoder drawPrimitives:lastPipeline->GetMTLPrimitiveTopology()
+ vertexStart:draw->firstVertex
+ vertexCount:draw->vertexCount
+ instanceCount:draw->instanceCount
+ baseInstance:draw->firstInstance];
+ }
}
} break;
@@ -1037,15 +1045,27 @@
// The index and instance count must be non-zero, otherwise no-op
if (draw->indexCount != 0 && draw->instanceCount != 0) {
- [encoder drawIndexedPrimitives:lastPipeline->GetMTLPrimitiveTopology()
- indexCount:draw->indexCount
- indexType:lastPipeline->GetMTLIndexType()
- indexBuffer:indexBuffer
- indexBufferOffset:indexBufferBaseOffset +
- draw->firstIndex * formatSize
- instanceCount:draw->instanceCount
- baseVertex:draw->baseVertex
- baseInstance:draw->firstInstance];
+ // MTLFeatureSet_iOS_GPUFamily3_v1 does not support baseInstance and
+ // baseVertex.
+ if (draw->baseVertex == 0 && draw->firstInstance == 0) {
+ [encoder drawIndexedPrimitives:lastPipeline->GetMTLPrimitiveTopology()
+ indexCount:draw->indexCount
+ indexType:lastPipeline->GetMTLIndexType()
+ indexBuffer:indexBuffer
+ indexBufferOffset:indexBufferBaseOffset +
+ draw->firstIndex * formatSize
+ instanceCount:draw->instanceCount];
+ } else {
+ [encoder drawIndexedPrimitives:lastPipeline->GetMTLPrimitiveTopology()
+ indexCount:draw->indexCount
+ indexType:lastPipeline->GetMTLIndexType()
+ indexBuffer:indexBuffer
+ indexBufferOffset:indexBufferBaseOffset +
+ draw->firstIndex * formatSize
+ instanceCount:draw->instanceCount
+ baseVertex:draw->baseVertex
+ baseInstance:draw->firstInstance];
+ }
}
} break;
diff --git a/src/dawn_native/metal/DeviceMTL.mm b/src/dawn_native/metal/DeviceMTL.mm
index 02873ac..d449d48 100644
--- a/src/dawn_native/metal/DeviceMTL.mm
+++ b/src/dawn_native/metal/DeviceMTL.mm
@@ -76,6 +76,15 @@
#endif
// TODO(crbug.com/dawn/342): Investigate emulation -- possibly expensive.
SetToggle(Toggle::MetalDisableSamplerCompare, !haveSamplerCompare);
+
+ bool haveBaseVertexBaseInstance = true;
+#if defined(DAWN_PLATFORM_IOS)
+ haveBaseVertexBaseInstance =
+ [mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1];
+#endif
+ // TODO(crbug.com/dawn/343): Investigate emulation.
+ SetToggle(Toggle::DisableBaseVertex, !haveBaseVertexBaseInstance);
+ SetToggle(Toggle::DisableBaseInstance, !haveBaseVertexBaseInstance);
}
// TODO(jiawei.shao@intel.com): tighten this workaround when the driver bug is fixed.
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 9bbf740..2194016 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -869,12 +869,23 @@
indexBufferBaseOffset),
draw->instanceCount, draw->baseVertex, draw->firstInstance);
} else {
- // This branch is only needed on OpenGL < 4.2
- gl.DrawElementsInstancedBaseVertex(
- lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType,
- reinterpret_cast<void*>(draw->firstIndex * formatSize +
- indexBufferBaseOffset),
- draw->instanceCount, draw->baseVertex);
+ // This branch is only needed on OpenGL < 4.2; ES < 3.2
+ if (draw->baseVertex != 0) {
+ gl.DrawElementsInstancedBaseVertex(
+ lastPipeline->GetGLPrimitiveTopology(), draw->indexCount,
+ formatType,
+ reinterpret_cast<void*>(draw->firstIndex * formatSize +
+ indexBufferBaseOffset),
+ draw->instanceCount, draw->baseVertex);
+ } else {
+ // This branch is only needed on OpenGL < 3.2; ES < 3.2
+ gl.DrawElementsInstanced(
+ lastPipeline->GetGLPrimitiveTopology(), draw->indexCount,
+ formatType,
+ reinterpret_cast<void*>(draw->firstIndex * formatSize +
+ indexBufferBaseOffset),
+ draw->instanceCount);
+ }
}
} break;
diff --git a/src/dawn_native/opengl/DeviceGL.cpp b/src/dawn_native/opengl/DeviceGL.cpp
index f6c2e1a..26d2c33 100644
--- a/src/dawn_native/opengl/DeviceGL.cpp
+++ b/src/dawn_native/opengl/DeviceGL.cpp
@@ -36,6 +36,7 @@
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions)
: DeviceBase(adapter, descriptor), gl(functions) {
+ InitTogglesFromDriver();
if (descriptor != nullptr) {
ApplyToggleOverrides(descriptor);
}
@@ -46,6 +47,30 @@
BaseDestructor();
}
+ void Device::InitTogglesFromDriver() {
+ bool supportsBaseVertex = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(3, 2);
+
+ bool supportsBaseInstance = gl.IsAtLeastGLES(3, 2) || gl.IsAtLeastGL(4, 2);
+
+ // TODO(crbug.com/dawn/343): We can support the extension variants, but need to load the EXT
+ // procs without the extension suffix.
+ // We'll also need emulation of shader builtins gl_BaseVertex and gl_BaseInstance.
+
+ // supportsBaseVertex |=
+ // (gl.IsAtLeastGLES(2, 0) &&
+ // (gl.IsGLExtensionSupported("OES_draw_elements_base_vertex") ||
+ // gl.IsGLExtensionSupported("EXT_draw_elements_base_vertex"))) ||
+ // (gl.IsAtLeastGL(3, 1) && gl.IsGLExtensionSupported("ARB_draw_elements_base_vertex"));
+
+ // supportsBaseInstance |=
+ // (gl.IsAtLeastGLES(3, 1) && gl.IsGLExtensionSupported("EXT_base_instance")) ||
+ // (gl.IsAtLeastGL(3, 1) && gl.IsGLExtensionSupported("ARB_base_instance"));
+
+ // TODO(crbug.com/dawn/343): Investigate emulation.
+ SetToggle(Toggle::DisableBaseVertex, !supportsBaseVertex);
+ SetToggle(Toggle::DisableBaseInstance, !supportsBaseInstance);
+ }
+
const GLFormat& Device::GetGLFormat(const Format& format) {
ASSERT(format.isSupported);
ASSERT(format.GetIndex() < mFormatTable.size());
diff --git a/src/dawn_native/opengl/DeviceGL.h b/src/dawn_native/opengl/DeviceGL.h
index 7d0b803..d9ec9c0 100644
--- a/src/dawn_native/opengl/DeviceGL.h
+++ b/src/dawn_native/opengl/DeviceGL.h
@@ -89,6 +89,7 @@
TextureBase* texture,
const TextureViewDescriptor* descriptor) override;
+ void InitTogglesFromDriver();
void CheckPassedFences();
void Destroy() override;
MaybeError WaitForIdleForDestruction() override;
diff --git a/src/dawn_native/opengl/OpenGLFunctions.cpp b/src/dawn_native/opengl/OpenGLFunctions.cpp
index 0bc5781..ba5b69a 100644
--- a/src/dawn_native/opengl/OpenGLFunctions.cpp
+++ b/src/dawn_native/opengl/OpenGLFunctions.cpp
@@ -74,12 +74,12 @@
return mSupportedGLExtensionsSet.count(extension) != 0;
}
- bool OpenGLFunctions::IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) {
+ bool OpenGLFunctions::IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) const {
return mStandard == Standard::Desktop &&
std::tie(mMajorVersion, mMinorVersion) >= std::tie(majorVersion, minorVersion);
}
- bool OpenGLFunctions::IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion) {
+ bool OpenGLFunctions::IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion) const {
return mStandard == Standard::ES &&
std::tie(mMajorVersion, mMinorVersion) >= std::tie(majorVersion, minorVersion);
}
diff --git a/src/dawn_native/opengl/OpenGLFunctions.h b/src/dawn_native/opengl/OpenGLFunctions.h
index 14c7e91..e514300 100644
--- a/src/dawn_native/opengl/OpenGLFunctions.h
+++ b/src/dawn_native/opengl/OpenGLFunctions.h
@@ -25,8 +25,8 @@
public:
MaybeError Initialize(GetProcAddress getProc);
- bool IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion);
- bool IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion);
+ bool IsAtLeastGL(uint32_t majorVersion, uint32_t minorVersion) const;
+ bool IsAtLeastGLES(uint32_t majorVersion, uint32_t minorVersion) const;
bool IsGLExtensionSupported(const char* extension) const;