Reland "Metal: add loadMSAAFromResolve support."
This is a reland of 9f82158f17
Original change's description:
> Metal: add loadMSAAFromResolve support.
>
> Also fixes some minor warnings.
>
> Bug: skia:12086
> Change-Id: Ia476a7a196b490022978761e92f935a6d668136a
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/441797
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Commit-Queue: Jim Van Verth <jvanverth@google.com>
Bug: skia:12086
Change-Id: I1d9dd36b3f8f19a0ab4a98ccaab18146566c1885
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/446077
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
be0e255c3e
commit
7efdc8fd5d
@ -51,6 +51,10 @@ public:
|
||||
|
||||
id<MTLTexture> mtlTexture() const { return fTexture; }
|
||||
|
||||
unsigned int sampleCount() const { return fTexture.sampleCount; }
|
||||
|
||||
bool framebufferOnly() const { return fTexture.framebufferOnly; }
|
||||
|
||||
protected:
|
||||
void onRelease() override;
|
||||
void onAbandon() override;
|
||||
|
@ -107,6 +107,10 @@ public:
|
||||
void finishOutstandingGpuWork() override;
|
||||
std::unique_ptr<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
|
||||
|
||||
bool loadMSAAFromResolve(GrAttachment* dst,
|
||||
GrMtlAttachment* src,
|
||||
const SkIRect& srcRect);
|
||||
|
||||
// When the Metal backend actually uses indirect command buffers, this function will actually do
|
||||
// what it says. For now, every command is encoded directly into the primary command buffer, so
|
||||
// this function is pretty useless, except for indicating that a render target has been drawn
|
||||
|
@ -147,7 +147,7 @@ GrOpsRenderPass* GrMtlGpu::onGetOpsRenderPass(
|
||||
// TODO: Make use of discardable MSAA
|
||||
bool withResolve = false;
|
||||
|
||||
// Figure out if we can use a Resolve store action for this render pass.
|
||||
// Figure out if we can use a Resolve store for this render pass
|
||||
if (useMSAASurface && mtlRT->resolveAttachment() &&
|
||||
this->mtlCaps().storeAndMultisampleResolveSupport()) {
|
||||
withResolve = true;
|
||||
@ -356,7 +356,7 @@ bool GrMtlGpu::uploadToTexture(GrMtlTexture* tex,
|
||||
|
||||
int currentWidth = rect.width();
|
||||
int currentHeight = rect.height();
|
||||
SkDEBUGCODE(int layerHeight = tex->height();)
|
||||
SkDEBUGCODE(int layerHeight = tex->height());
|
||||
MTLOrigin origin = MTLOriginMake(rect.left(), rect.top(), 0);
|
||||
|
||||
auto cmdBuffer = this->commandBuffer();
|
||||
@ -387,7 +387,7 @@ bool GrMtlGpu::uploadToTexture(GrMtlTexture* tex,
|
||||
}
|
||||
currentWidth = std::max(1, currentWidth/2);
|
||||
currentHeight = std::max(1, currentHeight/2);
|
||||
SkDEBUGCODE(layerHeight = currentHeight;)
|
||||
SkDEBUGCODE(layerHeight = currentHeight);
|
||||
}
|
||||
#ifdef SK_BUILD_FOR_MAC
|
||||
[mtlBuffer->mtlBuffer() didModifyRange: NSMakeRange(slice.fOffset, combinedBufferSize)];
|
||||
@ -1530,6 +1530,80 @@ void GrMtlGpu::resolve(GrMtlAttachment* resolveAttachment,
|
||||
this->commandBuffer()->addGrSurface(sk_ref_sp<const GrSurface>(msaaAttachment));
|
||||
}
|
||||
|
||||
bool GrMtlGpu::loadMSAAFromResolve(GrAttachment* dst,
|
||||
GrMtlAttachment* src,
|
||||
const SkIRect& srcRect) {
|
||||
if (!dst) {
|
||||
return false;
|
||||
}
|
||||
if (!src || src->framebufferOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrMtlAttachment* mtlDst = static_cast<GrMtlAttachment*>(dst);
|
||||
|
||||
auto renderPipeline = this->resourceProvider().findOrCreateMSAALoadPipeline(mtlDst->mtlFormat(),
|
||||
dst->numSamples());
|
||||
|
||||
// Set up rendercommandencoder
|
||||
auto renderPassDesc = [MTLRenderPassDescriptor new];
|
||||
auto colorAttachment = renderPassDesc.colorAttachments[0];
|
||||
colorAttachment.texture = mtlDst->mtlTexture();
|
||||
colorAttachment.loadAction = MTLLoadActionDontCare;
|
||||
colorAttachment.storeAction = MTLStoreActionMultisampleResolve;
|
||||
colorAttachment.resolveTexture = src->mtlTexture();
|
||||
|
||||
auto renderCmdEncoder =
|
||||
this->commandBuffer()->getRenderCommandEncoder(renderPassDesc, nullptr, nullptr);
|
||||
|
||||
// Bind pipeline
|
||||
renderCmdEncoder->setRenderPipelineState(renderPipeline->mtlPipelineState());
|
||||
this->commandBuffer()->addResource(sk_ref_sp(renderPipeline));
|
||||
|
||||
// Bind src as input texture
|
||||
renderCmdEncoder->setFragmentTexture(src->mtlTexture(), 0);
|
||||
// No sampler needed
|
||||
this->commandBuffer()->addGrSurface(sk_ref_sp<GrSurface>(src));
|
||||
|
||||
// Scissor and viewport should default to size of color attachment
|
||||
|
||||
// Update and bind uniform data
|
||||
int w = srcRect.width();
|
||||
int h = srcRect.height();
|
||||
|
||||
// dst rect edges in NDC (-1 to 1)
|
||||
int dw = dst->width();
|
||||
int dh = dst->height();
|
||||
float dx0 = 2.f * srcRect.fLeft / dw - 1.f;
|
||||
float dx1 = 2.f * (srcRect.fLeft + w) / dw - 1.f;
|
||||
float dy0 = 2.f * srcRect.fTop / dh - 1.f;
|
||||
float dy1 = 2.f * (srcRect.fTop + h) / dh - 1.f;
|
||||
|
||||
struct {
|
||||
float posXform[4];
|
||||
int textureSize[2];
|
||||
int pad[2];
|
||||
} uniData = {{dx1 - dx0, dy1 - dy0, dx0, dy0}, {dw, dh}, {0, 0}};
|
||||
|
||||
constexpr size_t uniformSize = 32;
|
||||
if (@available(macOS 10.11, iOS 8.3, *)) {
|
||||
SkASSERT(uniformSize <= this->caps()->maxPushConstantsSize());
|
||||
renderCmdEncoder->setVertexBytes(&uniData, uniformSize, 0);
|
||||
} else {
|
||||
// upload the data
|
||||
GrRingBuffer::Slice slice = this->uniformsRingBuffer()->suballocate(uniformSize);
|
||||
GrMtlBuffer* buffer = (GrMtlBuffer*) slice.fBuffer;
|
||||
char* destPtr = static_cast<char*>(slice.fBuffer->map()) + slice.fOffset;
|
||||
memcpy(destPtr, &uniData, uniformSize);
|
||||
|
||||
renderCmdEncoder->setVertexBuffer(buffer->mtlBuffer(), slice.fOffset, 0);
|
||||
}
|
||||
|
||||
renderCmdEncoder->drawPrimitives(MTLPrimitiveTypeTriangleStrip, (NSUInteger)0, (NSUInteger)4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if GR_TEST_UTILS
|
||||
void GrMtlGpu::testingOnly_startCapture() {
|
||||
if (@available(macOS 10.13, iOS 11.0, *)) {
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
fPipelineState = nil;
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> mtlPipelineState() { return fPipelineState; }
|
||||
id<MTLRenderPipelineState> mtlPipelineState() const { return fPipelineState; }
|
||||
|
||||
private:
|
||||
GrMtlRenderPipeline(id<MTLRenderPipelineState> pso)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "src/gpu/GrProgramDesc.h"
|
||||
#include "src/gpu/GrThreadSafePipelineBuilder.h"
|
||||
#include "src/gpu/mtl/GrMtlDepthStencil.h"
|
||||
#include "src/gpu/mtl/GrMtlPipeline.h"
|
||||
#include "src/gpu/mtl/GrMtlPipelineStateBuilder.h"
|
||||
#include "src/gpu/mtl/GrMtlSampler.h"
|
||||
|
||||
@ -39,6 +40,8 @@ public:
|
||||
// Finds or creates a compatible MTLSamplerState based on the GrSamplerState.
|
||||
GrMtlSampler* findOrCreateCompatibleSampler(GrSamplerState);
|
||||
|
||||
const GrMtlRenderPipeline* findOrCreateMSAALoadPipeline(MTLPixelFormat, int sampleCount);
|
||||
|
||||
// Destroy any cached resources. To be called before releasing the MtlDevice.
|
||||
void destroyResources();
|
||||
|
||||
@ -85,6 +88,14 @@ private:
|
||||
|
||||
SkTDynamicHash<GrMtlSampler, GrMtlSampler::Key> fSamplers;
|
||||
SkTDynamicHash<GrMtlDepthStencil, GrMtlDepthStencil::Key> fDepthStencilStates;
|
||||
|
||||
struct MSAALoadPipelineEntry {
|
||||
sk_sp<const GrMtlRenderPipeline> fPipeline;
|
||||
MTLPixelFormat fPixelFormat;
|
||||
int fSampleCount;
|
||||
};
|
||||
id<MTLLibrary> fMSAALoadLibrary;
|
||||
SkTArray<MSAALoadPipelineEntry> fMSAALoadPipelines;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "include/gpu/GrContextOptions.h"
|
||||
#include "include/gpu/GrDirectContext.h"
|
||||
#include "src/core/SkTraceEvent.h"
|
||||
#include "src/gpu/GrDirectContextPriv.h"
|
||||
#include "src/gpu/GrProgramDesc.h"
|
||||
#include "src/gpu/mtl/GrMtlCommandBuffer.h"
|
||||
@ -66,7 +67,93 @@ GrMtlSampler* GrMtlResourceProvider::findOrCreateCompatibleSampler(GrSamplerStat
|
||||
return sampler;
|
||||
}
|
||||
|
||||
const GrMtlRenderPipeline* GrMtlResourceProvider::findOrCreateMSAALoadPipeline(
|
||||
MTLPixelFormat pixelFormat, int sampleCount) {
|
||||
if (!fMSAALoadLibrary) {
|
||||
TRACE_EVENT0("skia", TRACE_FUNC);
|
||||
|
||||
SkSL::String shaderText;
|
||||
shaderText.append(
|
||||
"#include <metal_stdlib>\n"
|
||||
"#include <simd/simd.h>\n"
|
||||
"using namespace metal;\n"
|
||||
"\n"
|
||||
"typedef struct {\n"
|
||||
" float4 position [[position]];\n"
|
||||
"} VertexOutput;\n"
|
||||
"\n"
|
||||
"typedef struct {\n"
|
||||
" float4 uPosXform;\n"
|
||||
" uint2 uTextureSize;\n"
|
||||
"} VertexUniforms;\n"
|
||||
"\n"
|
||||
"vertex VertexOutput vertexMain(constant VertexUniforms& uniforms [[buffer(0)]],\n"
|
||||
" uint vertexID [[vertex_id]]) {\n"
|
||||
" VertexOutput out;\n"
|
||||
" float2 position = float2(float(vertexID >> 1), float(vertexID & 1));\n"
|
||||
" out.position.xy = position * uniforms.uPosXform.xy + uniforms.uPosXform.zw;\n"
|
||||
" out.position.zw = float2(0.0, 1.0);\n"
|
||||
" return out;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"fragment float4 fragmentMain(VertexOutput in [[stage_in]],\n"
|
||||
" texture2d<half> colorMap [[texture(0)]]) {\n"
|
||||
" uint2 coords = uint2(in.position.x, in.position.y);"
|
||||
" half4 colorSample = colorMap.read(coords);\n"
|
||||
" return float4(colorSample);\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler();
|
||||
fMSAALoadLibrary = GrCompileMtlShaderLibrary(fGpu, shaderText, errorHandler);
|
||||
if (!fMSAALoadLibrary) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < fMSAALoadPipelines.count(); ++i) {
|
||||
if (fMSAALoadPipelines[i].fPixelFormat == pixelFormat &&
|
||||
fMSAALoadPipelines[i].fSampleCount == sampleCount) {
|
||||
return fMSAALoadPipelines[i].fPipeline.get();
|
||||
}
|
||||
}
|
||||
|
||||
auto pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
|
||||
pipelineDescriptor.vertexFunction =
|
||||
[fMSAALoadLibrary newFunctionWithName: @"vertexMain"];
|
||||
pipelineDescriptor.fragmentFunction =
|
||||
[fMSAALoadLibrary newFunctionWithName: @"fragmentMain"];
|
||||
|
||||
auto mtlColorAttachment = [[MTLRenderPipelineColorAttachmentDescriptor alloc] init];
|
||||
|
||||
mtlColorAttachment.pixelFormat = pixelFormat;
|
||||
mtlColorAttachment.blendingEnabled = FALSE;
|
||||
mtlColorAttachment.writeMask = MTLColorWriteMaskAll;
|
||||
|
||||
pipelineDescriptor.colorAttachments[0] = mtlColorAttachment;
|
||||
|
||||
pipelineDescriptor.sampleCount = sampleCount;
|
||||
|
||||
NSError* error;
|
||||
auto pso =
|
||||
[fGpu->device() newRenderPipelineStateWithDescriptor: pipelineDescriptor
|
||||
error: &error];
|
||||
if (!pso) {
|
||||
SkDebugf("Error creating pipeline: %s\n",
|
||||
[[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
|
||||
}
|
||||
|
||||
auto renderPipeline = GrMtlRenderPipeline::Make(pso);
|
||||
|
||||
fMSAALoadPipelines.push_back({renderPipeline, pixelFormat, sampleCount});
|
||||
return fMSAALoadPipelines[fMSAALoadPipelines.count()-1].fPipeline.get();
|
||||
}
|
||||
|
||||
void GrMtlResourceProvider::destroyResources() {
|
||||
fMSAALoadLibrary = nil;
|
||||
fMSAALoadPipelines.reset();
|
||||
|
||||
fSamplers.foreach([&](GrMtlSampler* sampler) { sampler->unref(); });
|
||||
fSamplers.reset();
|
||||
|
||||
|
@ -17,11 +17,12 @@ GR_NORETAIN_BEGIN
|
||||
|
||||
static void finalize_helper(GrMtlVaryingHandler::VarArray& vars) {
|
||||
int locationIndex = 0;
|
||||
int componentCount = 0;
|
||||
|
||||
SkDEBUGCODE(int componentCount = 0);
|
||||
for (GrShaderVar& var : vars.items()) {
|
||||
// Metal only allows scalars (including bool and char) and vectors as varyings
|
||||
SkASSERT(GrSLTypeVecLength(var.getType()) != -1);
|
||||
componentCount += GrSLTypeVecLength(var.getType());
|
||||
SkDEBUGCODE(componentCount += GrSLTypeVecLength(var.getType()));
|
||||
|
||||
SkString location;
|
||||
location.appendf("location = %d", locationIndex);
|
||||
|
Loading…
Reference in New Issue
Block a user