Commit 1677cf14 by Le Hoang Quyen Committed by Commit Bot

Metal: Implement Uniform buffers

Uniform buffer is implemented in two forms: - If number of ubo used in shader program is low, each buffer will use one discrete Metal buffer slot. - If number of ubo used is large, they will be embedded into one Metal argument buffer. Argument buffer is similar to Vulkan descriptor set. This is due to limit of number of Metal's discrete buffer slots which is only 31 and over half of them are already used by vertex attributes, default uniforms, driver uniforms, etc. The downside is that whenever a buffer binding is changed, the argument buffer must be updated also. Added empty TransformFeedbackMtl implementation to enable ES3 context creation on Metal. Bug: angleproject:2634 Change-Id: I69325696fac735cb45ab88ab55468c0991abc317 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2408593 Commit-Queue: Le Hoang Quyen <le.hoang.q@gmail.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 962e3473
......@@ -10,8 +10,8 @@ Metal and MacOS, Chrome OS, and Fuchsia support.
| | Direct3D 9 | Direct3D 11 | Desktop GL | GL ES | Vulkan | Metal |
|----------------|:-------------:|:----------------:|:--------------:|:-------------:|:-------------:|:-------------:|
| OpenGL ES 2.0 | complete | complete | complete | complete | complete | in progress |
| OpenGL ES 3.0 | | complete | complete | complete | complete | |
| OpenGL ES 2.0 | complete | complete | complete | complete | complete | complete |
| OpenGL ES 3.0 | | complete | complete | complete | complete | in progress |
| OpenGL ES 3.1 | | in progress | complete | complete | complete | |
| OpenGL ES 3.2 | | | in progress | in progress | in progress | |
......
......@@ -35,6 +35,8 @@ _metal_backend_sources = [
"SurfaceMtl.mm",
"TextureMtl.h",
"TextureMtl.mm",
"TransformFeedbackMtl.h",
"TransformFeedbackMtl.mm",
"VertexArrayMtl.h",
"VertexArrayMtl.mm",
"mtl_buffer_pool.h",
......
......@@ -63,6 +63,13 @@ struct IndexConversionBufferMtl : public ConversionBufferMtl
const size_t offset;
};
struct UniformConversionBufferMtl : public ConversionBufferMtl
{
UniformConversionBufferMtl(ContextMtl *context, size_t offsetIn);
const size_t offset;
};
class BufferHolderMtl
{
public:
......@@ -138,6 +145,8 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
gl::DrawElementsType elemType,
size_t offset);
ConversionBufferMtl *getUniformConversionBuffer(ContextMtl *context, size_t offset);
size_t size() const { return static_cast<size_t>(mState.getSize()); }
private:
......@@ -166,10 +175,12 @@ class BufferMtl : public BufferImpl, public BufferHolderMtl
// GPU side buffers pool
mtl::BufferPool mBufferPool;
// A cache of converted vertex data.
// A cache of converted buffer data.
std::vector<VertexConversionBufferMtl> mVertexConversionBuffers;
std::vector<IndexConversionBufferMtl> mIndexConversionBuffers;
std::vector<UniformConversionBufferMtl> mUniformConversionBuffers;
};
class SimpleWeakBufferHolderMtl : public BufferHolderMtl
......
......@@ -63,6 +63,12 @@ IndexConversionBufferMtl::IndexConversionBufferMtl(ContextMtl *context,
offset(offsetIn)
{}
// UniformConversionBufferMtl implementation
UniformConversionBufferMtl::UniformConversionBufferMtl(ContextMtl *context, size_t offsetIn)
: ConversionBufferMtl(context, 0, mtl::kUniformBufferSettingOffsetMinAlignment),
offset(offsetIn)
{}
// VertexConversionBufferMtl implementation.
VertexConversionBufferMtl::VertexConversionBufferMtl(ContextMtl *context,
angle::FormatID formatIDIn,
......@@ -339,6 +345,20 @@ IndexConversionBufferMtl *BufferMtl::getIndexConversionBuffer(ContextMtl *contex
return &mIndexConversionBuffers.back();
}
ConversionBufferMtl *BufferMtl::getUniformConversionBuffer(ContextMtl *context, size_t offset)
{
for (UniformConversionBufferMtl &buffer : mUniformConversionBuffers)
{
if (buffer.offset == offset)
{
return &buffer;
}
}
mUniformConversionBuffers.emplace_back(context, offset);
return &mUniformConversionBuffers.back();
}
void BufferMtl::markConversionBuffersDirty()
{
for (VertexConversionBufferMtl &buffer : mVertexConversionBuffers)
......@@ -354,12 +374,20 @@ void BufferMtl::markConversionBuffersDirty()
buffer.convertedBuffer = nullptr;
buffer.convertedOffset = 0;
}
for (UniformConversionBufferMtl &buffer : mUniformConversionBuffers)
{
buffer.dirty = true;
buffer.convertedBuffer = nullptr;
buffer.convertedOffset = 0;
}
}
void BufferMtl::clearConversionBuffers()
{
mVertexConversionBuffers.clear();
mIndexConversionBuffers.clear();
mUniformConversionBuffers.clear();
}
angle::Result BufferMtl::setDataImpl(const gl::Context *context,
......
......@@ -420,7 +420,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
angle::Result handleDirtyDepthBias(const gl::Context *context);
angle::Result checkIfPipelineChanged(const gl::Context *context,
gl::PrimitiveMode primitiveMode,
Optional<mtl::RenderPipelineDesc> *changedPipelineDesc);
bool *isPipelineDescChanged);
angle::Result startOcclusionQueryInRenderPass(QueryMtl *query, bool clearOldValue);
......@@ -440,6 +440,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
DIRTY_BIT_CULL_MODE,
DIRTY_BIT_WINDING,
DIRTY_BIT_RENDER_PIPELINE,
DIRTY_BIT_UNIFORM_BUFFERS_BINDING,
DIRTY_BIT_MAX,
};
......
......@@ -22,6 +22,7 @@
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/ShaderMtl.h"
#include "libANGLE/renderer/metal/TextureMtl.h"
#include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
#include "libANGLE/renderer/metal/VertexArrayMtl.h"
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
#include "libANGLE/renderer/metal/mtl_format_utils.h"
......@@ -795,7 +796,7 @@ angle::Result ContextMtl::syncState(const gl::Context *context,
// NOTE(hqle): ES 3.0 feature.
break;
case gl::State::DIRTY_BIT_UNIFORM_BUFFER_BINDINGS:
// NOTE(hqle): ES 3.0 feature.
mDirtyBits.set(DIRTY_BIT_UNIFORM_BUFFERS_BINDING);
break;
case gl::State::DIRTY_BIT_ATOMIC_COUNTER_BUFFER_BINDING:
break;
......@@ -946,8 +947,7 @@ SyncImpl *ContextMtl::createSync()
TransformFeedbackImpl *ContextMtl::createTransformFeedback(const gl::TransformFeedbackState &state)
{
// NOTE(hqle): ES 3.0
UNIMPLEMENTED();
return nullptr;
return new TransformFeedbackMtl(state);
}
// Sampler object creation
......@@ -1644,8 +1644,10 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context,
ANGLE_TRY(startOcclusionQueryInRenderPass(mOcclusionQuery, false));
}
Optional<mtl::RenderPipelineDesc> changedPipelineDesc;
ANGLE_TRY(checkIfPipelineChanged(context, mode, &changedPipelineDesc));
bool isPipelineDescChanged;
ANGLE_TRY(checkIfPipelineChanged(context, mode, &isPipelineDescChanged));
bool uniformBuffersDirty = false;
for (size_t bit : mDirtyBits)
{
......@@ -1692,6 +1694,9 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context,
case DIRTY_BIT_RENDER_PIPELINE:
// Already handled. See checkIfPipelineChanged().
break;
case DIRTY_BIT_UNIFORM_BUFFERS_BINDING:
uniformBuffersDirty = true;
break;
default:
UNREACHABLE();
break;
......@@ -1700,7 +1705,8 @@ angle::Result ContextMtl::setupDraw(const gl::Context *context,
mDirtyBits.reset();
ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, changedPipelineDesc, textureChanged));
ANGLE_TRY(mProgram->setupDraw(context, &mRenderEncoder, mRenderPipelineDesc,
isPipelineDescChanged, textureChanged, uniformBuffersDirty));
if (mode == gl::PrimitiveMode::LineLoop)
{
......@@ -1892,10 +1898,9 @@ angle::Result ContextMtl::handleDirtyDepthBias(const gl::Context *context)
return angle::Result::Continue;
}
angle::Result ContextMtl::checkIfPipelineChanged(
const gl::Context *context,
gl::PrimitiveMode primitiveMode,
Optional<mtl::RenderPipelineDesc> *changedPipelineDesc)
angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context,
gl::PrimitiveMode primitiveMode,
bool *isPipelineDescChanged)
{
ASSERT(mRenderEncoder.valid());
mtl::PrimitiveTopologyClass topologyClass = mtl::GetPrimitiveTopologyClass(primitiveMode);
......@@ -1920,10 +1925,10 @@ angle::Result ContextMtl::checkIfPipelineChanged(
mRenderPipelineDesc.outputDescriptor.updateEnabledDrawBuffers(
mDrawFramebuffer->getState().getEnabledDrawBuffers());
*changedPipelineDesc = mRenderPipelineDesc;
}
*isPipelineDescChanged = rppChange;
return angle::Result::Continue;
}
}
......@@ -521,21 +521,20 @@ void DisplayMtl::ensureCapsInitialized() const
mNativeCaps.fragmentMediumpInt.setTwosComplementInt(32);
mNativeCaps.fragmentLowpInt.setTwosComplementInt(32);
GLuint maxUniformVectors = mtl::kDefaultUniformsMaxSize / (sizeof(GLfloat) * 4);
GLuint maxDefaultUniformVectors = mtl::kDefaultUniformsMaxSize / (sizeof(GLfloat) * 4);
const GLuint maxUniformComponents = maxUniformVectors * 4;
const GLuint maxDefaultUniformComponents = maxDefaultUniformVectors * 4;
// Uniforms are implemented using a uniform buffer, so the max number of uniforms we can
// support is the max buffer range divided by the size of a single uniform (4X float).
mNativeCaps.maxVertexUniformVectors = maxUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxUniformComponents;
mNativeCaps.maxFragmentUniformVectors = maxUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxUniformComponents;
mNativeCaps.maxVertexUniformVectors = maxDefaultUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Vertex] = maxDefaultUniformComponents;
mNativeCaps.maxFragmentUniformVectors = maxDefaultUniformVectors;
mNativeCaps.maxShaderUniformComponents[gl::ShaderType::Fragment] = maxDefaultUniformComponents;
// NOTE(hqle): support UBO (ES 3.0 feature)
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = 0;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = 0;
mNativeCaps.maxCombinedUniformBlocks = 0;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Vertex] = mtl::kMaxShaderUBOs;
mNativeCaps.maxShaderUniformBlocks[gl::ShaderType::Fragment] = mtl::kMaxShaderUBOs;
mNativeCaps.maxCombinedUniformBlocks = mtl::kMaxGLUBOBindings;
// Note that we currently implement textures as combined image+samplers, so the limit is
// the minimum of supported samplers and sampled images.
......@@ -550,18 +549,20 @@ void DisplayMtl::ensureCapsInitialized() const
mNativeCaps.maxCombinedShaderStorageBlocks = maxPerStageStorageBuffers;
// Fill in additional limits for UBOs and SSBOs.
mNativeCaps.maxUniformBufferBindings = 0;
mNativeCaps.maxUniformBlockSize = 0;
mNativeCaps.uniformBufferOffsetAlignment = 0;
mNativeCaps.maxUniformBufferBindings = mNativeCaps.maxCombinedUniformBlocks;
mNativeCaps.maxUniformBlockSize = mtl::kMaxUBOSize; // Default according to GLES 3.0 spec.
mNativeCaps.uniformBufferOffsetAlignment = 1;
mNativeCaps.maxShaderStorageBufferBindings = 0;
mNativeCaps.maxShaderStorageBlockSize = 0;
mNativeCaps.shaderStorageBufferOffsetAlignment = 0;
// NOTE(hqle): support UBO
const uint32_t maxCombinedUniformComponents =
maxDefaultUniformComponents + mtl::kMaxUBOSize * mtl::kMaxShaderUBOs / 4;
for (gl::ShaderType shaderType : gl::kAllGraphicsShaderTypes)
{
mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxUniformComponents;
mNativeCaps.maxCombinedShaderUniformComponents[shaderType] = maxCombinedUniformComponents;
}
mNativeCaps.maxCombinedShaderOutputResources = 0;
......
......@@ -18,6 +18,7 @@
#include "common/utilities.h"
#include "libANGLE/renderer/ProgramImpl.h"
#include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/metal/mtl_buffer_pool.h"
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
#include "libANGLE/renderer/metal/mtl_glslang_utils.h"
#include "libANGLE/renderer/metal/mtl_resources.h"
......@@ -27,15 +28,28 @@ namespace rx
{
class ContextMtl;
struct ProgramArgumentBufferEncoderMtl
{
void reset(ContextMtl *contextMtl);
mtl::AutoObjCPtr<id<MTLArgumentEncoder>> metalArgBufferEncoder;
mtl::BufferPool bufferPool;
};
// Represents a specialized shader variant. For example, a shader variant with fragment coverage
// mask enabled and a shader variant without.
struct ProgramShaderVariantMtl
struct ProgramShaderObjVariantMtl
{
void reset(ContextMtl *contextMtl);
mtl::AutoObjCPtr<id<MTLFunction>> metalShader;
// NOTE(hqle): might need additional info such as uniform buffer encoder, fragment coverage mask
// enabled or not, etc.
// UBO's argument buffer encoder. Used when number of UBOs used exceeds number of allowed
// discrete slots, and thus needs to encode all into one argument buffer.
ProgramArgumentBufferEncoderMtl uboArgBufferEncoder;
// Store reference to the TranslatedShaderInfo to easy querying mapped textures/UBO/XFB
// bindings.
const mtl::TranslatedShaderInfo *translatedSrcInfo;
};
class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecializeShaderFactory
......@@ -124,8 +138,10 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
// shader program changed.
angle::Result setupDraw(const gl::Context *glContext,
mtl::RenderCommandEncoder *cmdEncoder,
const Optional<mtl::RenderPipelineDesc> &changedPipelineDesc,
bool forceTexturesSetting);
const mtl::RenderPipelineDesc &pipelineDesc,
bool pipelineDescChanged,
bool forceTexturesSetting,
bool uniformBuffersDirty);
private:
template <int cols, int rows>
......@@ -146,16 +162,32 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
mtl::RenderCommandEncoder *cmdEncoder,
bool forceUpdate);
angle::Result updateUniformBuffers(ContextMtl *context,
mtl::RenderCommandEncoder *cmdEncoder,
const mtl::RenderPipelineDesc &pipelineDesc);
angle::Result legalizeUniformBufferOffsets(ContextMtl *context,
const std::vector<gl::InterfaceBlock> &blocks);
angle::Result bindUniformBuffersToDiscreteSlots(ContextMtl *context,
mtl::RenderCommandEncoder *cmdEncoder,
const std::vector<gl::InterfaceBlock> &blocks,
gl::ShaderType shaderType);
angle::Result encodeUniformBuffersInfoArgumentBuffer(
ContextMtl *context,
mtl::RenderCommandEncoder *cmdEncoder,
const std::vector<gl::InterfaceBlock> &blocks,
gl::ShaderType shaderType);
void reset(ContextMtl *context);
void linkResources(const gl::ProgramLinkedResources &resources);
angle::Result linkImpl(const gl::Context *glContext,
const gl::ProgramLinkedResources &resources,
gl::InfoLog &infoLog);
angle::Result createMslShaderLib(const gl::Context *glContext,
angle::Result createMslShaderLib(mtl::Context *context,
gl::ShaderType shaderType,
gl::InfoLog &infoLog,
const std::string &translatedSource);
mtl::TranslatedShaderInfo *translatedMslInfo);
// State for the default uniform blocks.
struct DefaultUniformBlock final : private angle::NonCopyable
......@@ -175,16 +207,25 @@ class ProgramMtl : public ProgramImpl, public mtl::RenderPipelineCacheSpecialize
gl::ShaderBitSet mSamplerBindingsDirty;
gl::ShaderMap<DefaultUniformBlock> mDefaultUniformBlocks;
gl::ShaderMap<std::string> mTranslatedMslShader;
// Translated metal shaders:
gl::ShaderMap<mtl::TranslatedShaderInfo> mMslShaderTranslateInfo;
gl::ShaderMap<mtl::AutoObjCPtr<id<MTLLibrary>>> mMslShaderLibrary;
// Shader variants:
// - Vertex shader: One variant for now.
std::array<ProgramShaderVariantMtl, 1> mVertexShaderVariants;
// Compiled native shader object variants:
// - Vertex shader: one variant for now.
std::array<ProgramShaderObjVariantMtl, 1> mVertexShaderVariants;
// - Fragment shader: One with sample coverage mask enabled, one with it disabled.
std::array<ProgramShaderVariantMtl, 2> mFragmentShaderVariants;
std::array<ProgramShaderObjVariantMtl, 2> mFragmentShaderVariants;
// Cached references of current shader variants.
gl::ShaderMap<ProgramShaderObjVariantMtl *> mCurrentShaderVariants;
// Scratch data:
// Legalized buffers and their offsets. For example, uniform buffer's offset=1 is not a valid
// offset, it will be converted to legal offset and the result is stored in this array.
std::vector<std::pair<mtl::BufferRef, uint32_t>> mLegalizedOffsetedUniformBuffers;
// Stores the render stages usage of each uniform buffer. Only used if the buffers are encoded
// into an argument buffer.
std::vector<uint32_t> mArgumentBufferRenderStageUsages;
mtl::RenderPipelineCache mMetalRenderPipelineCache;
};
......
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// TransformFeedbackMtl.h:
// Defines the class interface for TransformFeedbackMtl, implementing TransformFeedbackImpl.
//
#ifndef LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
#define LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
#include "libANGLE/renderer/TransformFeedbackImpl.h"
namespace gl
{
class ProgramState;
} // namespace gl
namespace rx
{
class TransformFeedbackMtl : public TransformFeedbackImpl
{
public:
TransformFeedbackMtl(const gl::TransformFeedbackState &state);
~TransformFeedbackMtl() override;
angle::Result begin(const gl::Context *context, gl::PrimitiveMode primitiveMode) override;
angle::Result end(const gl::Context *context) override;
angle::Result pause(const gl::Context *context) override;
angle::Result resume(const gl::Context *context) override;
angle::Result bindIndexedBuffer(const gl::Context *context,
size_t index,
const gl::OffsetBindingPointer<gl::Buffer> &binding) override;
private:
};
} // namespace rx
#endif // LIBANGLE_RENDERER_METAL_TRANSFORMFEEDBACKMTL_H_
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// TransformFeedbackMtl.mm:
// Defines the class interface for TransformFeedbackMtl, implementing TransformFeedbackImpl.
//
#include "libANGLE/renderer/metal/TransformFeedbackMtl.h"
#include "libANGLE/Context.h"
#include "libANGLE/Query.h"
#include "common/debug.h"
namespace rx
{
TransformFeedbackMtl::TransformFeedbackMtl(const gl::TransformFeedbackState &state)
: TransformFeedbackImpl(state)
{}
TransformFeedbackMtl::~TransformFeedbackMtl() {}
angle::Result TransformFeedbackMtl::begin(const gl::Context *context,
gl::PrimitiveMode primitiveMode)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
angle::Result TransformFeedbackMtl::end(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
angle::Result TransformFeedbackMtl::pause(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
angle::Result TransformFeedbackMtl::resume(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
angle::Result TransformFeedbackMtl::bindIndexedBuffer(
const gl::Context *context,
size_t index,
const gl::OffsetBindingPointer<gl::Buffer> &binding)
{
UNIMPLEMENTED();
return angle::Result::Continue;
}
} // namespace rx
......@@ -418,6 +418,10 @@ class RenderCommandEncoder final : public CommandEncoder
RenderCommandEncoder &setVisibilityResultMode(MTLVisibilityResultMode mode, size_t offset);
RenderCommandEncoder &useResource(const BufferRef &resource,
MTLResourceUsage usage,
mtl::RenderStages states);
RenderCommandEncoder &setColorStoreAction(MTLStoreAction action, uint32_t colorAttachmentIndex);
// Set store action for every color attachment.
RenderCommandEncoder &setColorStoreAction(MTLStoreAction action);
......
......@@ -62,7 +62,8 @@ namespace
PROC(DrawIndexed) \
PROC(DrawIndexedInstanced) \
PROC(DrawIndexedInstancedBaseVertex) \
PROC(SetVisibilityResultMode)
PROC(SetVisibilityResultMode) \
PROC(UseResource)
#define ANGLE_MTL_TYPE_DECL(CMD) CMD,
......@@ -325,6 +326,25 @@ void SetVisibilityResultModeCmd(id<MTLRenderCommandEncoder> encoder,
[encoder setVisibilityResultMode:mode offset:offset];
}
void UseResourceCmd(id<MTLRenderCommandEncoder> encoder, IntermediateCommandStream *stream)
{
id<MTLResource> resource = stream->fetch<id<MTLResource>>();
MTLResourceUsage usage = stream->fetch<MTLResourceUsage>();
mtl::RenderStages stages = stream->fetch<mtl::RenderStages>();
ANGLE_UNUSED_VARIABLE(stages);
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
{
[encoder useResource:resource usage:usage stages:stages];
}
else
#endif
{
[encoder useResource:resource usage:usage];
}
[resource ANGLE_MTL_RELEASE];
}
// Command encoder mapping
#define ANGLE_MTL_CMD_MAP(CMD) CMD##Cmd,
......@@ -1422,6 +1442,25 @@ RenderCommandEncoder &RenderCommandEncoder::setVisibilityResultMode(MTLVisibilit
return *this;
}
RenderCommandEncoder &RenderCommandEncoder::useResource(const BufferRef &resource,
MTLResourceUsage usage,
mtl::RenderStages states)
{
if (!resource)
{
return *this;
}
cmdBuffer().setReadDependency(resource);
mCommands.push(CmdType::UseResource)
.push([resource->get() ANGLE_MTL_RETAIN])
.push(usage)
.push(states);
return *this;
}
RenderCommandEncoder &RenderCommandEncoder::setColorStoreAction(MTLStoreAction action,
uint32_t colorAttachmentIndex)
{
......
......@@ -99,6 +99,9 @@ constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
// NOTE(hqle): support variable max number of render targets
constexpr uint32_t kMaxRenderTargets = 4;
constexpr uint32_t kMaxShaderUBOs = 12;
constexpr uint32_t kMaxUBOSize = 16384;
// The max size of a buffer that will be allocated in shared memory.
// NOTE(hqle): This is just a hint. There is no official document on what is the max allowed size
// for shared memory.
......@@ -120,10 +123,12 @@ constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 256;
constexpr uint32_t kUniformBufferSettingOffsetMinAlignment = 4;
#endif
constexpr uint32_t kIndexBufferOffsetAlignment = 4;
constexpr uint32_t kArgumentBufferOffsetAlignment = kUniformBufferSettingOffsetMinAlignment;
constexpr uint32_t kTextureToBufferBlittingAlignment = 256;
// Front end binding limits
constexpr uint32_t kMaxGLSamplerBindings = 2 * kMaxShaderSamplers;
constexpr uint32_t kMaxGLUBOBindings = 2 * kMaxShaderUBOs;
// Binding index start for vertex data buffers:
constexpr uint32_t kVboBindingIndexStart = 0;
......@@ -134,6 +139,8 @@ constexpr uint32_t kDefaultAttribsBindingIndex = kVboBindingIndexStart + kMaxVer
constexpr uint32_t kDriverUniformsBindingIndex = kDefaultAttribsBindingIndex + 1;
// Binding index for default uniforms:
constexpr uint32_t kDefaultUniformsBindingIndex = kDefaultAttribsBindingIndex + 3;
// Binding index for UBO's argument buffer or starting discrete slot
constexpr uint32_t kUBOArgumentBufferBindingIndex = kDefaultUniformsBindingIndex + 1;
constexpr uint32_t kStencilMaskAll = 0xff; // Only 8 bits stencil is supported
......@@ -146,8 +153,7 @@ constexpr float kEmulatedAlphaValue = 1.0f;
constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t);
// NOTE(hqle): Support ES 3.0.
constexpr gl::Version kMaxSupportedGLVersion = gl::Version(2, 0);
constexpr gl::Version kMaxSupportedGLVersion = gl::Version(3, 0);
// Work-around the enum is not available on macOS
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
......@@ -156,6 +162,16 @@ constexpr MTLBlitOption kBlitOptionRowLinearPVRTC = MTLBlitOptionNone;
constexpr MTLBlitOption kBlitOptionRowLinearPVRTC = MTLBlitOptionRowLinearPVRTC;
#endif
#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
using RenderStages = MTLRenderStages;
constexpr MTLRenderStages kRenderStageVertex = MTLRenderStageVertex;
constexpr MTLRenderStages kRenderStageFragment = MTLRenderStageFragment;
#else
using RenderStages = int;
constexpr RenderStages kRenderStageVertex = 1;
constexpr RenderStages kRenderStageFragment = 2;
#endif
enum class PixelType
{
Int,
......
......@@ -28,8 +28,16 @@ struct SamplerBinding
struct TranslatedShaderInfo
{
void reset();
// Translated Metal source code
std::string metalShaderSource;
// Metal library compiled from source code above. Used by ProgramMtl.
AutoObjCPtr<id<MTLLibrary>> metalLibrary;
std::array<SamplerBinding, kMaxGLSamplerBindings> actualSamplerBindings;
// NOTE(hqle): UBO, XFB bindings.
std::array<uint32_t, kMaxGLUBOBindings> actualUBOBindings;
bool hasUBOArgumentBuffer;
};
void GlslangGetShaderSource(const gl::ProgramState &programState,
......@@ -48,8 +56,7 @@ angle::Result GlslangGetShaderSpirvCode(ErrorHandler *context,
angle::Result SpirvCodeToMsl(Context *context,
const gl::ProgramState &programState,
gl::ShaderMap<std::vector<uint32_t>> *sprivShaderCode,
gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut,
gl::ShaderMap<std::string> *mslCodeOut);
gl::ShaderMap<TranslatedShaderInfo> *mslShaderInfoOut);
} // namespace mtl
} // namespace rx
......
......@@ -2403,7 +2403,7 @@ TEST_P(UniformBufferTest, UniformBlocksInDiffProgramShareUniformBuffer)
// buffer data correctly.
TEST_P(UniformBufferTest, UniformBlocksSharedSameUniformBuffer)
{
ANGLE_SKIP_TEST_IF(IsIntel() && IsOSX());
ANGLE_SKIP_TEST_IF(IsIntel() && IsOSX() && IsOpenGL());
GLint64 maxUniformBlockSize;
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
......@@ -2842,7 +2842,7 @@ TEST_P(UniformBufferTest, UniformBlockWithOneLargeVec4Array)
TEST_P(UniformBufferTest, UniformBlockWithOneLargeMatrixArrayWithRowMajorQualifier)
{
// http://anglebug.com/3837 , http://anglebug.com/2273
ANGLE_SKIP_TEST_IF(IsOSX() || IsAndroid() || (IsAMD() && IsOpenGL()) ||
ANGLE_SKIP_TEST_IF((IsOSX() && IsOpenGL()) || IsAndroid() || (IsAMD() && IsOpenGL()) ||
(IsLinux() && IsIntel() && IsOpenGL()));
GLint64 maxUniformBlockSize;
glGetInteger64v(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
......@@ -3096,7 +3096,7 @@ TEST_P(UniformBufferTest, InstanceArrayUniformBlockWithOneLargeMatrixArray)
TEST_P(UniformBufferTest, Std140UniformBlockWithDynamicallyIndexedRowMajorArray)
{
// http://anglebug.com/3837 , http://anglebug.com/2273
ANGLE_SKIP_TEST_IF((IsLinux() && IsIntel() && IsOpenGL()) || IsOSX());
ANGLE_SKIP_TEST_IF(((IsLinux() && IsIntel()) || IsOSX()) && IsOpenGL());
constexpr char kFS[] =
R"(#version 300 es
......@@ -3180,9 +3180,78 @@ void main(void){
EXPECT_GL_NO_ERROR();
}
// Test with many uniform buffers work as expected.
TEST_P(UniformBufferTest, ManyBlocks)
{
// http://anglebug.com/5039
ANGLE_SKIP_TEST_IF(IsD3D11());
constexpr char kFS[] =
R"(#version 300 es
precision highp float;
out vec4 my_FragColor;
layout(std140) uniform uboBlock { vec4 color; } blocks[12];
void main()
{
vec4 color = vec4(0, 0, 0, 1);
color += blocks[0].color;
color += blocks[1].color;
color += blocks[2].color;
color += blocks[3].color;
color += blocks[4].color;
color += blocks[5].color;
color += blocks[6].color;
color += blocks[7].color;
color += blocks[8].color;
color += blocks[9].color;
color += blocks[10].color;
color += blocks[11].color;
my_FragColor = vec4(color.rgb, 1.0);
})";
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
GLBuffer buffers[12];
GLint bufferIndex[12];
bufferIndex[0] = glGetUniformBlockIndex(program, "uboBlock[0]");
bufferIndex[1] = glGetUniformBlockIndex(program, "uboBlock[1]");
bufferIndex[2] = glGetUniformBlockIndex(program, "uboBlock[2]");
bufferIndex[3] = glGetUniformBlockIndex(program, "uboBlock[3]");
bufferIndex[4] = glGetUniformBlockIndex(program, "uboBlock[4]");
bufferIndex[5] = glGetUniformBlockIndex(program, "uboBlock[5]");
bufferIndex[6] = glGetUniformBlockIndex(program, "uboBlock[6]");
bufferIndex[7] = glGetUniformBlockIndex(program, "uboBlock[7]");
bufferIndex[8] = glGetUniformBlockIndex(program, "uboBlock[8]");
bufferIndex[9] = glGetUniformBlockIndex(program, "uboBlock[9]");
bufferIndex[10] = glGetUniformBlockIndex(program, "uboBlock[10]");
bufferIndex[11] = glGetUniformBlockIndex(program, "uboBlock[11]");
std::vector<GLubyte> v(16, 0);
float *vAsFloat = reinterpret_cast<float *>(v.data());
for (int i = 0; i < 12; ++i)
{
glBindBuffer(GL_UNIFORM_BUFFER, buffers[i]);
vAsFloat[0] = (i + 1) / 255.0f;
vAsFloat[1] = (i + 1) / 255.0f;
vAsFloat[2] = (i + 1) / 255.0f;
vAsFloat[3] = 255.0f;
glBufferData(GL_UNIFORM_BUFFER, v.size(), v.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, i, buffers[i]);
glUniformBlockBinding(program, bufferIndex[i], i);
}
drawQuad(program.get(), essl3_shaders::PositionAttrib(), 0.5f);
EXPECT_PIXEL_NEAR(0, 0, 78, 78, 78, 255, 2);
}
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES3(UniformBufferTest);
ANGLE_INSTANTIATE_TEST_ES3_AND(UniformBufferTest, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES31(UniformBufferTest31);
} // namespace
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