Commit 3e1e1087 by Le Hoang Quyen Committed by Commit Bot

Metal: Use 2d array for caching index conversion's pipeline state.

For index conversion utils, use 2d array for caching compute pipeline state based on DrawElementsType & source offset is aligned or not, instead of using std::map as previously. Also moved default shader's initialization to DisplayMtl. New test added: IndexBufferOffsetTest.DrawAtDifferentOffsetAlignments Bug: angleproject:2634 Change-Id: I1bd77aca88e03229ef8053e32add66733e33b06e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2192569 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 9905f7f5
...@@ -109,6 +109,8 @@ class DisplayMtl : public DisplayImpl ...@@ -109,6 +109,8 @@ class DisplayMtl : public DisplayImpl
mtl::RenderUtils &getUtils() { return mUtils; } mtl::RenderUtils &getUtils() { return mUtils; }
mtl::StateCache &getStateCache() { return mStateCache; } mtl::StateCache &getStateCache() { return mStateCache; }
id<MTLLibrary> getDefaultShadersLib() const { return mDefaultShaders; }
id<MTLDepthStencilState> getDepthStencilState(const mtl::DepthStencilDesc &desc) id<MTLDepthStencilState> getDepthStencilState(const mtl::DepthStencilDesc &desc)
{ {
return mStateCache.getDepthStencilState(getMetalDevice(), desc); return mStateCache.getDepthStencilState(getMetalDevice(), desc);
...@@ -143,6 +145,7 @@ class DisplayMtl : public DisplayImpl ...@@ -143,6 +145,7 @@ class DisplayMtl : public DisplayImpl
void initializeExtensions() const; void initializeExtensions() const;
void initializeTextureCaps() const; void initializeTextureCaps() const;
void initializeFeatures(); void initializeFeatures();
angle::Result initializeShaderLibrary();
mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil; mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
...@@ -152,6 +155,9 @@ class DisplayMtl : public DisplayImpl ...@@ -152,6 +155,9 @@ class DisplayMtl : public DisplayImpl
mtl::StateCache mStateCache; mtl::StateCache mStateCache;
mtl::RenderUtils mUtils; mtl::RenderUtils mUtils;
// Built-in Shaders
mtl::AutoObjCPtr<id<MTLLibrary>> mDefaultShaders = nil;
angle::PackedEnumMap<gl::TextureType, mtl::TextureRef> mNullTextures; angle::PackedEnumMap<gl::TextureType, mtl::TextureRef> mNullTextures;
mutable bool mCapsInitialized; mutable bool mCapsInitialized;
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#include "libANGLE/renderer/metal/ContextMtl.h" #include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.h" #include "libANGLE/renderer/metal/SurfaceMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h" #include "libANGLE/renderer/metal/mtl_common.h"
#include "libANGLE/renderer/metal/shaders/compiled/mtl_default_shaders.inc"
#include "libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc"
#include "platform/Platform.h" #include "platform/Platform.h"
#include "EGL/eglext.h" #include "EGL/eglext.h"
...@@ -25,7 +27,11 @@ namespace rx ...@@ -25,7 +27,11 @@ namespace rx
bool IsMetalDisplayAvailable() bool IsMetalDisplayAvailable()
{ {
// We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0. // We only support macos 10.13+ and 11 for now. Since they are requirements for Metal 2.0.
#if TARGET_OS_SIMULATOR
if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 13))
#else
if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 11)) if (ANGLE_APPLE_AVAILABLE_XCI(10.13, 13.0, 11))
#endif
{ {
return true; return true;
} }
...@@ -81,6 +87,7 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display) ...@@ -81,6 +87,7 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display)
} }
ANGLE_TRY(mFormatTable.initialize(this)); ANGLE_TRY(mFormatTable.initialize(this));
ANGLE_TRY(initializeShaderLibrary());
return mUtils.initialize(); return mUtils.initialize();
} }
...@@ -94,6 +101,7 @@ void DisplayMtl::terminate() ...@@ -94,6 +101,7 @@ void DisplayMtl::terminate()
} }
mUtils.onDestroy(); mUtils.onDestroy();
mCmdQueue.reset(); mCmdQueue.reset();
mDefaultShaders = nil;
mMetalDevice = nil; mMetalDevice = nil;
mCapsInitialized = false; mCapsInitialized = false;
...@@ -674,4 +682,28 @@ void DisplayMtl::initializeFeatures() ...@@ -674,4 +682,28 @@ void DisplayMtl::initializeFeatures()
platform->overrideFeaturesMtl(platform, &mFeatures); platform->overrideFeaturesMtl(platform, &mFeatures);
} }
angle::Result DisplayMtl::initializeShaderLibrary()
{
mtl::AutoObjCObj<NSError> err = nil;
#if defined(ANGLE_MTL_DEBUG_INTERNAL_SHADERS)
mDefaultShaders = CreateShaderLibrary(getMetalDevice(), default_metallib_src,
sizeof(default_metallib_src), &err);
#else
mDefaultShaders = CreateShaderLibraryFromBinary(getMetalDevice(), compiled_default_metallib,
compiled_default_metallib_len, &err);
#endif
if (err && !mDefaultShaders)
{
ANGLE_MTL_OBJC_SCOPE
{
ERR() << "Internal error: " << err.get().localizedDescription.UTF8String;
}
return angle::Result::Stop;
}
return angle::Result::Continue;
}
} // namespace rx } // namespace rx
...@@ -126,7 +126,6 @@ class RenderUtils : public Context, angle::NonCopyable ...@@ -126,7 +126,6 @@ class RenderUtils : public Context, angle::NonCopyable
const char *function, const char *function,
unsigned int line) override; unsigned int line) override;
angle::Result initShaderLibrary();
void initClearResources(); void initClearResources();
void initBlitResources(); void initBlitResources();
...@@ -172,24 +171,20 @@ class RenderUtils : public Context, angle::NonCopyable ...@@ -172,24 +171,20 @@ class RenderUtils : public Context, angle::NonCopyable
const gl::Context *context, const gl::Context *context,
const IndexGenerationParams &params); const IndexGenerationParams &params);
AutoObjCPtr<id<MTLLibrary>> mDefaultShaders = nil;
RenderPipelineCache mClearRenderPipelineCache; RenderPipelineCache mClearRenderPipelineCache;
RenderPipelineCache mBlitRenderPipelineCache; RenderPipelineCache mBlitRenderPipelineCache;
RenderPipelineCache mBlitPremultiplyAlphaRenderPipelineCache; RenderPipelineCache mBlitPremultiplyAlphaRenderPipelineCache;
RenderPipelineCache mBlitUnmultiplyAlphaRenderPipelineCache; RenderPipelineCache mBlitUnmultiplyAlphaRenderPipelineCache;
struct IndexConvesionPipelineCacheKey // Index generator compute pipelines:
{ // - First dimension: index type.
gl::DrawElementsType srcType; // - second dimension: source buffer's offset is aligned or not.
bool srcBufferOffsetAligned; using IndexConversionPipelineArray =
std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
bool operator==(const IndexConvesionPipelineCacheKey &other) const; angle::EnumSize<gl::DrawElementsType>()>;
bool operator<(const IndexConvesionPipelineCacheKey &other) const;
}; IndexConversionPipelineArray mIndexConversionPipelineCaches;
std::map<IndexConvesionPipelineCacheKey, AutoObjCPtr<id<MTLComputePipelineState>>> IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
mIndexConversionPipelineCaches;
std::map<IndexConvesionPipelineCacheKey, AutoObjCPtr<id<MTLComputePipelineState>>>
mTriFanFromElemArrayGeneratorPipelineCaches;
AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline; AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline;
}; };
......
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
#include "libANGLE/renderer/metal/DisplayMtl.h" #include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h" #include "libANGLE/renderer/metal/mtl_common.h"
#include "libANGLE/renderer/metal/mtl_utils.h" #include "libANGLE/renderer/metal/mtl_utils.h"
#include "libANGLE/renderer/metal/shaders/compiled/mtl_default_shaders.inc"
#include "libANGLE/renderer/metal/shaders/mtl_default_shaders_src_autogen.inc"
namespace rx namespace rx
{ {
...@@ -98,39 +96,32 @@ void GetFirstLastIndicesFromClientElements(GLsizei count, ...@@ -98,39 +96,32 @@ void GetFirstLastIndicesFromClientElements(GLsizei count,
memcpy(lastOut, indices + count - 1, sizeof(indices[0])); memcpy(lastOut, indices + count - 1, sizeof(indices[0]));
} }
} // namespace template <typename T>
void ClearPipelineStateArray(T *pipelineCacheArray)
bool RenderUtils::IndexConvesionPipelineCacheKey::operator==(
const IndexConvesionPipelineCacheKey &other) const
{
return srcType == other.srcType && srcBufferOffsetAligned == other.srcBufferOffsetAligned;
}
bool RenderUtils::IndexConvesionPipelineCacheKey::operator<(
const IndexConvesionPipelineCacheKey &other) const
{ {
if (!srcBufferOffsetAligned && other.srcBufferOffsetAligned) for (auto &pipeline : *pipelineCacheArray)
{ {
return true; pipeline = nil;
} }
if (srcBufferOffsetAligned && !other.srcBufferOffsetAligned) }
template <typename T>
void ClearPipelineState2DArray(T *pipelineCache2DArray)
{
for (auto &level1Array : *pipelineCache2DArray)
{ {
return false; ClearPipelineStateArray(&level1Array);
} }
return static_cast<int>(srcType) < static_cast<int>(other.srcType);
} }
} // namespace
RenderUtils::RenderUtils(DisplayMtl *display) : Context(display) {} RenderUtils::RenderUtils(DisplayMtl *display) : Context(display) {}
RenderUtils::~RenderUtils() {} RenderUtils::~RenderUtils() {}
angle::Result RenderUtils::initialize() angle::Result RenderUtils::initialize()
{ {
auto re = initShaderLibrary();
if (re != angle::Result::Continue)
{
return re;
}
initClearResources(); initClearResources();
initBlitResources(); initBlitResources();
...@@ -139,15 +130,13 @@ angle::Result RenderUtils::initialize() ...@@ -139,15 +130,13 @@ angle::Result RenderUtils::initialize()
void RenderUtils::onDestroy() void RenderUtils::onDestroy()
{ {
mDefaultShaders = nil;
mClearRenderPipelineCache.clear(); mClearRenderPipelineCache.clear();
mBlitRenderPipelineCache.clear(); mBlitRenderPipelineCache.clear();
mBlitPremultiplyAlphaRenderPipelineCache.clear(); mBlitPremultiplyAlphaRenderPipelineCache.clear();
mBlitUnmultiplyAlphaRenderPipelineCache.clear(); mBlitUnmultiplyAlphaRenderPipelineCache.clear();
mIndexConversionPipelineCaches.clear(); ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
mTriFanFromElemArrayGeneratorPipelineCaches.clear(); ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
mTriFanFromArraysGeneratorPipeline = nil; mTriFanFromArraysGeneratorPipeline = nil;
} }
...@@ -176,37 +165,16 @@ void RenderUtils::handleError(NSError *nserror, ...@@ -176,37 +165,16 @@ void RenderUtils::handleError(NSError *nserror,
<< nserror.localizedDescription.UTF8String; << nserror.localizedDescription.UTF8String;
} }
angle::Result RenderUtils::initShaderLibrary()
{
AutoObjCObj<NSError> err = nil;
#if defined(ANGLE_MTL_DEBUG_INTERNAL_SHADERS)
mDefaultShaders = CreateShaderLibrary(getDisplay()->getMetalDevice(), default_metallib_src,
sizeof(default_metallib_src), &err);
#else
mDefaultShaders =
CreateShaderLibraryFromBinary(getDisplay()->getMetalDevice(), compiled_default_metallib,
compiled_default_metallib_len, &err);
#endif
if (err && !mDefaultShaders)
{
ANGLE_MTL_CHECK(this, false, err.get());
return angle::Result::Stop;
}
return angle::Result::Continue;
}
void RenderUtils::initClearResources() void RenderUtils::initClearResources()
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
// Shader pipeline // Shader pipeline
mClearRenderPipelineCache.setVertexShader( mClearRenderPipelineCache.setVertexShader(
this, [[mDefaultShaders.get() newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]); this, [[shaderLib newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]);
mClearRenderPipelineCache.setFragmentShader( mClearRenderPipelineCache.setFragmentShader(
this, [[mDefaultShaders.get() newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]); this, [[shaderLib newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]);
} }
} }
...@@ -214,8 +182,9 @@ void RenderUtils::initBlitResources() ...@@ -214,8 +182,9 @@ void RenderUtils::initBlitResources()
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
auto shaderLib = mDefaultShaders.get(); id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
auto vertexShader = [[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE]; id<MTLFunction> vertexShader =
[[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE];
mBlitRenderPipelineCache.setVertexShader(this, vertexShader); mBlitRenderPipelineCache.setVertexShader(this, vertexShader);
mBlitRenderPipelineCache.setFragmentShader( mBlitRenderPipelineCache.setFragmentShader(
...@@ -537,18 +506,16 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getIndexConversionPipeline ...@@ -537,18 +506,16 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getIndexConversionPipeline
{ {
id<MTLDevice> metalDevice = context->getMetalDevice(); id<MTLDevice> metalDevice = context->getMetalDevice();
size_t elementSize = gl::GetDrawElementsTypeSize(srcType); size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
bool aligned = (srcOffset % elementSize) == 0; BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
IndexConvesionPipelineCacheKey key = {srcType, aligned}; auto &cache = mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0];
auto &cache = mIndexConversionPipelineCaches[key];
if (!cache) if (!cache)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
auto shaderLib = mDefaultShaders.get(); id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil; id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil; NSError *err = nil;
...@@ -601,18 +568,17 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGene ...@@ -601,18 +568,17 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGene
{ {
id<MTLDevice> metalDevice = context->getMetalDevice(); id<MTLDevice> metalDevice = context->getMetalDevice();
size_t elementSize = gl::GetDrawElementsTypeSize(srcType); size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
bool aligned = (srcOffset % elementSize) == 0; BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
IndexConvesionPipelineCacheKey key = {srcType, aligned};
auto &cache = mTriFanFromElemArrayGeneratorPipelineCaches[key]; auto &cache = mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache) if (!cache)
{ {
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
auto shaderLib = mDefaultShaders.get(); id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil; id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE]; auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil; NSError *err = nil;
...@@ -677,7 +643,7 @@ angle::Result RenderUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl ...@@ -677,7 +643,7 @@ angle::Result RenderUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl
ANGLE_MTL_OBJC_SCOPE ANGLE_MTL_OBJC_SCOPE
{ {
id<MTLDevice> metalDevice = context->getMetalDevice(); id<MTLDevice> metalDevice = context->getMetalDevice();
auto shaderLib = mDefaultShaders.get(); id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
NSError *err = nil; NSError *err = nil;
id<MTLFunction> shader = [shaderLib newFunctionWithName:@"genTriFanIndicesFromArray"]; id<MTLFunction> shader = [shaderLib newFunctionWithName:@"genTriFanIndicesFromArray"];
......
...@@ -173,6 +173,49 @@ TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsets) ...@@ -173,6 +173,49 @@ TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsets)
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
} }
// Uses index buffer offset and 2 drawElement calls one of the other, one has aligned
// offset and one doesn't
TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsetAlignments)
{
GLubyte indexData8[] = {0, 1, 0, 1, 2, 3};
GLushort indexData16[] = {0, 1, 2, 1, 2, 3};
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
size_t indexDataWidth16 = 6 * sizeof(GLushort);
GLuint buffer[2];
glGenBuffers(2, buffer);
glUseProgram(mProgram);
glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(mPositionAttributeLocation);
// 8 bit index with aligned offset
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData8), indexData8, GL_DYNAMIC_DRAW);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(2));
// 16 bits index buffer, which unaligned offset
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth16, indexData16, GL_DYNAMIC_DRAW);
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
reinterpret_cast<void *>(indexDataWidth16 / 2));
// Check the upper left triangle
EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
// Check the down right triangle
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
EXPECT_GL_NO_ERROR();
}
// Uses index buffer offset and 2 drawElement calls one of the other with different counts, // Uses index buffer offset and 2 drawElement calls one of the other with different counts,
// makes sure the second drawElement call will have its data available. // makes sure the second drawElement call will have its data available.
TEST_P(IndexBufferOffsetTest, DrawWithDifferentCountsSameOffset) TEST_P(IndexBufferOffsetTest, DrawWithDifferentCountsSameOffset)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment