Hash :
ab42afa6
Author :
Date :
2019-11-21T10:13:44
Metal: fix vertex attribute's conversion lost after changing buffer binding. After vertex buffer's attribute is converted and stored in conversion buffer. Binding the same attribute to another buffer, then binding it back to previous buffer will result in previous conversion information lost. The conversion method would skip the conversion due to buffer's content hadn't been changed, however it didn't reuse the old conversion result. This CL also changed the way binding offset is used in Metal backend. - Previous, the offset would be assigned to the offset field of MTLVertexAttributeDescriptor, then the buffer would simply be bound to the command encoder with offset=0 i.e. setVertexBuffer(buffer, index, 0) - However this approach has several disadvantages. Since Metal doesn't allow MTLVertexAttributeDescriptor's offset to be larger than the vertex attribute's stride, the old approach would force the back-end to convert the attribute and store in conversion buffer. New approach: - MTLVertexAttributeDescriptor's offset will be zero. The offset will be used to bind the buffer itself to the render command encoder. i.e. setVertexBuffer(buffer, index, offset) This way the "offset <= stride" restriction no longer exists. The only restriction is the offset must be multiple of attribute's size. Added 3 new tests: - SimpleStateChangeTest.RebindTranslatedAttribute - VertexAttributeTest.DrawWithLargeBufferOffset - VertexAttributeTest.DrawWithLargeBufferOffsetAndLessComponents Bug: angleproject:2634 Change-Id: I6c2fa8091436e4a24405d791f86d17d97df02d64 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1940009 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
//
// Copyright 2019 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.
//
// mtl_render_utils.h:
// Defines the class interface for RenderUtils.
//
#ifndef LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
#define LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_
#import <Metal/Metal.h>
#include "libANGLE/angletypes.h"
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
#include "libANGLE/renderer/metal/mtl_state_cache.h"
namespace rx
{
class BufferMtl;
class ContextMtl;
class DisplayMtl;
namespace mtl
{
struct ClearRectParams : public ClearOptions
{
gl::Rectangle clearArea;
bool flipY = false;
};
struct BlitParams
{
gl::Offset dstOffset;
// Destination texture needs to have viewport Y flipped?
// The difference between this param and unpackFlipY is that unpackFlipY is from
// glCopyImageCHROMIUM(), and dstFlipY controls whether the final viewport needs to be
// flipped when drawing to destination texture.
bool dstFlipY = false;
MTLColorWriteMask dstColorMask = MTLColorWriteMaskAll;
TextureRef src;
uint32_t srcLevel = 0;
gl::Rectangle srcRect;
bool srcYFlipped = false; // source texture has data flipped in Y direction
bool unpackFlipY = false; // flip texture data copying process in Y direction
bool unpackPremultiplyAlpha = false;
bool unpackUnmultiplyAlpha = false;
bool dstLuminance = false;
};
struct TriFanFromArrayParams
{
uint32_t firstVertex;
uint32_t vertexCount;
BufferRef dstBuffer;
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset;
};
struct IndexGenerationParams
{
gl::DrawElementsType srcType;
GLsizei indexCount;
const void *indices;
BufferRef dstBuffer;
uint32_t dstOffset;
};
class RenderUtils : public Context, angle::NonCopyable
{
public:
RenderUtils(DisplayMtl *display);
~RenderUtils() override;
angle::Result initialize();
void onDestroy();
// Clear current framebuffer
void clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams ¶ms);
// Blit texture data to current framebuffer
void blitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams ¶ms);
angle::Result convertIndexBuffer(const gl::Context *context,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
uint32_t srcOffset,
const BufferRef &dstBuffer,
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset);
angle::Result generateTriFanBufferFromArrays(const gl::Context *context,
const TriFanFromArrayParams ¶ms);
angle::Result generateTriFanBufferFromElementsArray(const gl::Context *context,
const IndexGenerationParams ¶ms);
angle::Result generateLineLoopLastSegment(const gl::Context *context,
uint32_t firstVertex,
uint32_t lastVertex,
const BufferRef &dstBuffer,
uint32_t dstOffset);
angle::Result generateLineLoopLastSegmentFromElementsArray(const gl::Context *context,
const IndexGenerationParams ¶ms);
angle::Result dispatchCompute(const gl::Context *context,
ComputeCommandEncoder *encoder,
id<MTLComputePipelineState> pipelineState,
size_t numThreads);
private:
// override ErrorHandler
void handleError(GLenum error,
const char *file,
const char *function,
unsigned int line) override;
void handleError(NSError *_Nullable error,
const char *file,
const char *function,
unsigned int line) override;
angle::Result initShaderLibrary();
void initClearResources();
void initBlitResources();
void setupClearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams ¶ms);
void setupBlitWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams ¶ms);
id<MTLDepthStencilState> getClearDepthStencilState(const gl::Context *context,
const ClearRectParams ¶ms);
id<MTLRenderPipelineState> getClearRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const ClearRectParams ¶ms);
id<MTLRenderPipelineState> getBlitRenderPipelineState(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const BlitParams ¶ms);
void setupBlitWithDrawUniformData(RenderCommandEncoder *cmdEncoder, const BlitParams ¶ms);
void setupDrawCommonStates(RenderCommandEncoder *cmdEncoder);
AutoObjCPtr<id<MTLComputePipelineState>> getIndexConversionPipeline(
ContextMtl *context,
gl::DrawElementsType srcType,
uint32_t srcOffset);
AutoObjCPtr<id<MTLComputePipelineState>> getTriFanFromElemArrayGeneratorPipeline(
ContextMtl *context,
gl::DrawElementsType srcType,
uint32_t srcOffset);
angle::Result ensureTriFanFromArrayGeneratorInitialized(ContextMtl *context);
angle::Result generateTriFanBufferFromElementsArrayGPU(
const gl::Context *context,
gl::DrawElementsType srcType,
uint32_t indexCount,
const BufferRef &srcBuffer,
uint32_t srcOffset,
const BufferRef &dstBuffer,
// Must be multiples of kIndexBufferOffsetAlignment
uint32_t dstOffset);
angle::Result generateTriFanBufferFromElementsArrayCPU(const gl::Context *context,
const IndexGenerationParams ¶ms);
angle::Result generateLineLoopLastSegmentFromElementsArrayCPU(
const gl::Context *context,
const IndexGenerationParams ¶ms);
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;
AutoObjCPtr<id<MTLComputePipelineState>> mTriFanFromArraysGeneratorPipeline;
};
} // namespace mtl
} // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_MTL_RENDER_UTILS_H_ */