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
mtl::RenderUtils &getUtils() { return mUtils; }
mtl::StateCache &getStateCache() { return mStateCache; }
id<MTLLibrary> getDefaultShadersLib() const { return mDefaultShaders; }
id<MTLDepthStencilState> getDepthStencilState(const mtl::DepthStencilDesc &desc)
{
return mStateCache.getDepthStencilState(getMetalDevice(), desc);
......@@ -143,6 +145,7 @@ class DisplayMtl : public DisplayImpl
void initializeExtensions() const;
void initializeTextureCaps() const;
void initializeFeatures();
angle::Result initializeShaderLibrary();
mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
......@@ -152,6 +155,9 @@ class DisplayMtl : public DisplayImpl
mtl::StateCache mStateCache;
mtl::RenderUtils mUtils;
// Built-in Shaders
mtl::AutoObjCPtr<id<MTLLibrary>> mDefaultShaders = nil;
angle::PackedEnumMap<gl::TextureType, mtl::TextureRef> mNullTextures;
mutable bool mCapsInitialized;
......
......@@ -15,6 +15,8 @@
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.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 "EGL/eglext.h"
......@@ -25,7 +27,11 @@ namespace rx
bool IsMetalDisplayAvailable()
{
// 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))
#endif
{
return true;
}
......@@ -81,6 +87,7 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display)
}
ANGLE_TRY(mFormatTable.initialize(this));
ANGLE_TRY(initializeShaderLibrary());
return mUtils.initialize();
}
......@@ -94,6 +101,7 @@ void DisplayMtl::terminate()
}
mUtils.onDestroy();
mCmdQueue.reset();
mDefaultShaders = nil;
mMetalDevice = nil;
mCapsInitialized = false;
......@@ -674,4 +682,28 @@ void DisplayMtl::initializeFeatures()
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
......@@ -126,7 +126,6 @@ class RenderUtils : public Context, angle::NonCopyable
const char *function,
unsigned int line) override;
angle::Result initShaderLibrary();
void initClearResources();
void initBlitResources();
......@@ -172,24 +171,20 @@ class RenderUtils : public Context, angle::NonCopyable
const gl::Context *context,
const IndexGenerationParams &params);
AutoObjCPtr<id<MTLLibrary>> mDefaultShaders = nil;
RenderPipelineCache mClearRenderPipelineCache;
RenderPipelineCache mBlitRenderPipelineCache;
RenderPipelineCache mBlitPremultiplyAlphaRenderPipelineCache;
RenderPipelineCache mBlitUnmultiplyAlphaRenderPipelineCache;
struct IndexConvesionPipelineCacheKey
{
gl::DrawElementsType srcType;
bool srcBufferOffsetAligned;
bool operator==(const IndexConvesionPipelineCacheKey &other) const;
bool operator<(const IndexConvesionPipelineCacheKey &other) const;
};
std::map<IndexConvesionPipelineCacheKey, AutoObjCPtr<id<MTLComputePipelineState>>>
mIndexConversionPipelineCaches;
std::map<IndexConvesionPipelineCacheKey, AutoObjCPtr<id<MTLComputePipelineState>>>
mTriFanFromElemArrayGeneratorPipelineCaches;
// Index generator compute pipelines:
// - First dimension: index type.
// - second dimension: source buffer's offset is aligned or not.
using IndexConversionPipelineArray =
std::array<std::array<AutoObjCPtr<id<MTLComputePipelineState>>, 2>,
angle::EnumSize<gl::DrawElementsType>()>;
IndexConversionPipelineArray mIndexConversionPipelineCaches;
IndexConversionPipelineArray mTriFanFromElemArrayGeneratorPipelineCaches;
AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline;
};
......
......@@ -17,8 +17,6 @@
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/mtl_common.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
{
......@@ -98,39 +96,32 @@ void GetFirstLastIndicesFromClientElements(GLsizei count,
memcpy(lastOut, indices + count - 1, sizeof(indices[0]));
}
} // namespace
bool RenderUtils::IndexConvesionPipelineCacheKey::operator==(
const IndexConvesionPipelineCacheKey &other) const
{
return srcType == other.srcType && srcBufferOffsetAligned == other.srcBufferOffsetAligned;
}
bool RenderUtils::IndexConvesionPipelineCacheKey::operator<(
const IndexConvesionPipelineCacheKey &other) const
template <typename T>
void ClearPipelineStateArray(T *pipelineCacheArray)
{
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() {}
angle::Result RenderUtils::initialize()
{
auto re = initShaderLibrary();
if (re != angle::Result::Continue)
{
return re;
}
initClearResources();
initBlitResources();
......@@ -139,15 +130,13 @@ angle::Result RenderUtils::initialize()
void RenderUtils::onDestroy()
{
mDefaultShaders = nil;
mClearRenderPipelineCache.clear();
mBlitRenderPipelineCache.clear();
mBlitPremultiplyAlphaRenderPipelineCache.clear();
mBlitUnmultiplyAlphaRenderPipelineCache.clear();
mIndexConversionPipelineCaches.clear();
mTriFanFromElemArrayGeneratorPipelineCaches.clear();
ClearPipelineState2DArray(&mIndexConversionPipelineCaches);
ClearPipelineState2DArray(&mTriFanFromElemArrayGeneratorPipelineCaches);
mTriFanFromArraysGeneratorPipeline = nil;
}
......@@ -176,37 +165,16 @@ void RenderUtils::handleError(NSError *nserror,
<< 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()
{
ANGLE_MTL_OBJC_SCOPE
{
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
// Shader pipeline
mClearRenderPipelineCache.setVertexShader(
this, [[mDefaultShaders.get() newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]);
this, [[shaderLib newFunctionWithName:@"clearVS"] ANGLE_MTL_AUTORELEASE]);
mClearRenderPipelineCache.setFragmentShader(
this, [[mDefaultShaders.get() newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]);
this, [[shaderLib newFunctionWithName:@"clearFS"] ANGLE_MTL_AUTORELEASE]);
}
}
......@@ -214,8 +182,9 @@ void RenderUtils::initBlitResources()
{
ANGLE_MTL_OBJC_SCOPE
{
auto shaderLib = mDefaultShaders.get();
auto vertexShader = [[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE];
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> vertexShader =
[[shaderLib newFunctionWithName:@"blitVS"] ANGLE_MTL_AUTORELEASE];
mBlitRenderPipelineCache.setVertexShader(this, vertexShader);
mBlitRenderPipelineCache.setFragmentShader(
......@@ -537,18 +506,16 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getIndexConversionPipeline
{
id<MTLDevice> metalDevice = context->getMetalDevice();
size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
bool aligned = (srcOffset % elementSize) == 0;
IndexConvesionPipelineCacheKey key = {srcType, aligned};
auto &cache = mIndexConversionPipelineCaches[key];
BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
auto &cache = mIndexConversionPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache)
{
ANGLE_MTL_OBJC_SCOPE
{
auto shaderLib = mDefaultShaders.get();
id<MTLFunction> shader = nil;
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil;
......@@ -601,18 +568,17 @@ AutoObjCPtr<id<MTLComputePipelineState>> RenderUtils::getTriFanFromElemArrayGene
{
id<MTLDevice> metalDevice = context->getMetalDevice();
size_t elementSize = gl::GetDrawElementsTypeSize(srcType);
bool aligned = (srcOffset % elementSize) == 0;
IndexConvesionPipelineCacheKey key = {srcType, aligned};
BOOL aligned = (srcOffset % elementSize) == 0;
int srcTypeKey = static_cast<int>(srcType);
auto &cache = mTriFanFromElemArrayGeneratorPipelineCaches[key];
auto &cache = mTriFanFromElemArrayGeneratorPipelineCaches[srcTypeKey][aligned ? 1 : 0];
if (!cache)
{
ANGLE_MTL_OBJC_SCOPE
{
auto shaderLib = mDefaultShaders.get();
id<MTLFunction> shader = nil;
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
id<MTLFunction> shader = nil;
auto funcConstants = [[[MTLFunctionConstantValues alloc] init] ANGLE_MTL_AUTORELEASE];
NSError *err = nil;
......@@ -677,7 +643,7 @@ angle::Result RenderUtils::ensureTriFanFromArrayGeneratorInitialized(ContextMtl
ANGLE_MTL_OBJC_SCOPE
{
id<MTLDevice> metalDevice = context->getMetalDevice();
auto shaderLib = mDefaultShaders.get();
id<MTLLibrary> shaderLib = getDisplay()->getDefaultShadersLib();
NSError *err = nil;
id<MTLFunction> shader = [shaderLib newFunctionWithName:@"genTriFanIndicesFromArray"];
......
......@@ -173,6 +173,49 @@ TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsets)
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,
// makes sure the second drawElement call will have its data available.
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