Skip to content

Commit

Permalink
implemented GrMtlPipelineState for metal gpu backend
Browse files Browse the repository at this point in the history
Bug: skia:
Change-Id: I4284b760411d9ec24cccfb89352406dbb696c3c9
Reviewed-on: https://skia-review.googlesource.com/145896
Commit-Queue: Timothy Liang <timliang@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
  • Loading branch information
Timothy Liang authored and Skia Commit-Bot committed Aug 10, 2018
1 parent 7b8875d commit 6ed6396
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 17 deletions.
98 changes: 90 additions & 8 deletions src/gpu/mtl/GrMtlPipelineState.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,114 @@
#define GrMtlPipelineState_DEFINED

#include "GrMtlBuffer.h"
#include "GrMtlPipelineStateDataManager.h"
#include "glsl/GrGLSLProgramBuilder.h"

#import <metal/metal.h>

class GrMtlGpu;
class GrMtlPipelineStateDataManager;
class GrMtlSampler;
class GrMtlTexture;
class GrPipeline;

/**
* Wraps a MTLRenderPipelineState object and also contains more info about the pipeline as needed
* by Ganesh
*/
class GrMtlPipelineState {
public:
GrMtlPipelineState(GrMtlGpu* gpu,
id<MTLRenderPipelineState> pipelineState,
MTLPixelFormat pixelFormat,
GrMtlBuffer* geometryUniformBuffer,
GrMtlBuffer* fragmentUniformBuffer);
using UniformInfoArray = GrMtlPipelineStateDataManager::UniformInfoArray;
using UniformHandle = GrGLSLProgramDataManager::UniformHandle;

GrMtlPipelineState(
GrMtlGpu* gpu,
id<MTLRenderPipelineState> pipelineState,
MTLPixelFormat pixelFormat,
const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
GrMtlBuffer* geometryUniformBuffer,
GrMtlBuffer* fragmentUniformBuffer,
uint32_t numSamplers,
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
std::unique_ptr<GrGLSLXferProcessor> xferPRocessor,
std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
int fFragmentProcessorCnt);

id<MTLRenderPipelineState> mtlPipelineState() { return fPipelineState; }

void setData(const GrPrimitiveProcessor& primPRoc, const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]);

void bind(id<MTLRenderCommandEncoder>);

private:
GrMtlGpu* fGpu;
/**
* We use the RT's size and origin to adjust from Skia device space to Metal normalized device
* space and to make device space positions have the correct origin for processors that require
* them.
*/
struct RenderTargetState {
SkISize fRenderTargetSize;
GrSurfaceOrigin fRenderTargetOrigin;

RenderTargetState() { this->invalidate(); }
void invalidate() {
fRenderTargetSize.fWidth = -1;
fRenderTargetSize.fHeight = -1;
fRenderTargetOrigin = (GrSurfaceOrigin)-1;
}

/**
* Gets a float4 that adjusts the position from Skia device coords to Metals normalized
* device coords. Assuming the transformed position, pos, is a homogeneous float3, the vec,
* v, is applied as such:
* pos.x = dot(v.xy, pos.xz)
* pos.y = dot(v.zw, pos.yz)
*/
void getRTAdjustmentVec(float* destVec) {
destVec[0] = 2.f / fRenderTargetSize.fWidth;
destVec[1] = -1.f;
if (kBottomLeft_GrSurfaceOrigin == fRenderTargetOrigin) {
destVec[2] = -2.f / fRenderTargetSize.fHeight;
destVec[3] = 1.f;
} else {
destVec[2] = 2.f / fRenderTargetSize.fHeight;
destVec[3] = -1.f;
}
}
};

void setRenderTargetState(const GrRenderTargetProxy*);

struct SamplerBindings {
id<MTLSamplerState> fSampler;
id<MTLTexture> fTexture;
GrShaderFlags fVisibility;

SamplerBindings(const GrSamplerState& state, GrTexture* texture, GrShaderFlags flags,
GrMtlGpu*);
};

GrMtlGpu* fGpu;
id<MTLRenderPipelineState> fPipelineState;
MTLPixelFormat fPixelFormat;
sk_sp<GrMtlBuffer> fGeometryUniformBuffer;
sk_sp<GrMtlBuffer> fFragmentUniformBuffer;

RenderTargetState fRenderTargetState;
GrGLSLBuiltinUniformHandles fBuiltinUniformHandles;

sk_sp<GrMtlBuffer> fGeometryUniformBuffer;
sk_sp<GrMtlBuffer> fFragmentUniformBuffer;

int fNumSamplers;
SkTArray<SamplerBindings> fSamplerBindings;

std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor;
std::unique_ptr<GrGLSLXferProcessor> fXferProcessor;
std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors;
int fFragmentProcessorCnt;

GrMtlPipelineStateDataManager fDataManager;
};

#endif
155 changes: 148 additions & 7 deletions src/gpu/mtl/GrMtlPipelineState.mm
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,160 @@

#include "GrMtlPipelineState.h"

#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrPipeline.h"
#include "GrRenderTarget.h"
#include "GrTexturePriv.h"
#include "GrMtlBuffer.h"
#include "GrMtlGpu.h"
#include "GrMtlSampler.h"
#include "GrMtlTexture.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLGeometryProcessor.h"
#include "glsl/GrGLSLXferProcessor.h"

GrMtlPipelineState::GrMtlPipelineState(GrMtlGpu* gpu,
id<MTLRenderPipelineState> pipelineState,
MTLPixelFormat pixelFormat,
GrMtlBuffer* geometryUniformBuffer,
GrMtlBuffer* fragmentUniformBuffer)
GrMtlPipelineState::SamplerBindings::SamplerBindings(const GrSamplerState& state,
GrTexture* texture,
GrShaderFlags flags,
GrMtlGpu* gpu)
: fTexture(static_cast<GrMtlTexture*>(texture)->mtlTexture())
, fVisibility(flags) {
// TODO: use resource provider to get sampler.
std::unique_ptr<GrMtlSampler> sampler(
GrMtlSampler::Create(gpu, state, texture->texturePriv().maxMipMapLevel()));
fSampler = sampler->mtlSamplerState();
}

GrMtlPipelineState::GrMtlPipelineState(
GrMtlGpu* gpu,
id<MTLRenderPipelineState> pipelineState,
MTLPixelFormat pixelFormat,
const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
GrMtlBuffer* geometryUniformBuffer,
GrMtlBuffer* fragmentUniformBuffer,
uint32_t numSamplers,
std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor,
std::unique_ptr<GrGLSLXferProcessor> xferProcessor,
std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors,
int fragmentProcessorCnt)
: fGpu(gpu)
, fPipelineState(pipelineState)
, fPixelFormat(pixelFormat)
, fBuiltinUniformHandles(builtinUniformHandles)
, fGeometryUniformBuffer(geometryUniformBuffer)
, fFragmentUniformBuffer(fragmentUniformBuffer) {
(void) fGpu; // Suppress unused-var warning.
, fFragmentUniformBuffer(fragmentUniformBuffer)
, fNumSamplers(numSamplers)
, fGeometryProcessor(std::move(geometryProcessor))
, fXferProcessor(std::move(xferProcessor))
, fFragmentProcessors(std::move(fragmentProcessors))
, fFragmentProcessorCnt(fragmentProcessorCnt)
, fDataManager(uniforms, geometryUniformBuffer->sizeInBytes(),
fragmentUniformBuffer->sizeInBytes()) {
(void) fPixelFormat; // Suppress unused-var warning.
}

void GrMtlPipelineState::setData(const GrPrimitiveProcessor& primProc,
const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]) {
SkASSERT(primProcTextures || !primProc.numTextureSamplers());

this->setRenderTargetState(pipeline.proxy());
fGeometryProcessor->setData(fDataManager, primProc,
GrFragmentProcessor::CoordTransformIter(pipeline));
fSamplerBindings.reset();
for (int i = 0; i < primProc.numTextureSamplers(); ++i) {
const auto& sampler = primProc.textureSampler(i);
auto texture = static_cast<GrMtlTexture*>(primProcTextures[i]->peekTexture());
fSamplerBindings.emplace_back(sampler.samplerState(), texture, sampler.visibility(), fGpu);
}

GrFragmentProcessor::Iter iter(pipeline);
GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt);
const GrFragmentProcessor* fp = iter.next();
GrGLSLFragmentProcessor* glslFP = glslIter.next();
while (fp && glslFP) {
glslFP->setData(fDataManager, *fp);
for (int i = 0; i < fp->numTextureSamplers(); ++i) {
const auto& sampler = fp->textureSampler(i);
fSamplerBindings.emplace_back(sampler.samplerState(), sampler.peekTexture(),
kFragment_GrShaderFlag, fGpu);
}
fp = iter.next();
glslFP = glslIter.next();
}
SkASSERT(!fp && !glslFP);

{
SkIPoint offset;
GrTexture* dstTexture = pipeline.peekDstTexture(&offset);

fXferProcessor->setData(fDataManager, pipeline.getXferProcessor(), dstTexture, offset);
}

if (GrTextureProxy* dstTextureProxy = pipeline.dstTextureProxy()) {
fSamplerBindings.emplace_back(GrSamplerState::ClampNearest(),
dstTextureProxy->peekTexture(),
kFragment_GrShaderFlag,
fGpu);
}

SkASSERT(fNumSamplers == fSamplerBindings.count());
if (fGeometryUniformBuffer || fFragmentUniformBuffer) {
fDataManager.uploadUniformBuffers(fGpu, fGeometryUniformBuffer.get(),
fFragmentUniformBuffer.get());
}
}

void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) {
if (fGeometryUniformBuffer) {
[renderCmdEncoder setVertexBuffer: fGeometryUniformBuffer->mtlBuffer()
offset: 0
atIndex: GrMtlUniformHandler::kGeometryBinding];
}
if (fFragmentUniformBuffer) {
[renderCmdEncoder setFragmentBuffer: fFragmentUniformBuffer->mtlBuffer()
offset: 0
atIndex: GrMtlUniformHandler::kFragBinding];
}
SkASSERT(fNumSamplers == fSamplerBindings.count());
for (int index = 0; index < fNumSamplers; ++index) {
if (fSamplerBindings[index].fVisibility & kVertex_GrShaderFlag) {
[renderCmdEncoder setVertexTexture: fSamplerBindings[index].fTexture
atIndex: index];
[renderCmdEncoder setVertexSamplerState: fSamplerBindings[index].fSampler
atIndex: index];
}
if (fSamplerBindings[index].fVisibility & kFragment_GrShaderFlag) {
[renderCmdEncoder setFragmentTexture: fSamplerBindings[index].fTexture
atIndex: index];
[renderCmdEncoder setFragmentSamplerState: fSamplerBindings[index].fSampler
atIndex: index];
}
}
}

void GrMtlPipelineState::setRenderTargetState(const GrRenderTargetProxy* proxy) {
GrRenderTarget* rt = proxy->peekRenderTarget();

// Load the RT height uniform if it is needed to y-flip gl_FragCoord.
if (fBuiltinUniformHandles.fRTHeightUni.isValid() &&
fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) {
fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height()));
}

// set RT adjustment
SkISize size;
size.set(rt->width(), rt->height());
SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid());
if (fRenderTargetState.fRenderTargetOrigin != proxy->origin() ||
fRenderTargetState.fRenderTargetSize != size) {
fRenderTargetState.fRenderTargetSize = size;
fRenderTargetState.fRenderTargetOrigin = proxy->origin();

float rtAdjustmentVec[4];
fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec);
fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec);
}
}
11 changes: 9 additions & 2 deletions src/gpu/mtl/GrMtlPipelineStateBuilder.mm
Original file line number Diff line number Diff line change
Expand Up @@ -359,17 +359,24 @@ static MTLBlendOperation blend_equation_to_mtl_blend_op(GrBlendEquation equation
if (error) {
SkDebugf("Error creating pipeline: %s\n",
[[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
pipelineState = nil;
return nullptr;
}
return new GrMtlPipelineState(fGpu,
pipelineState,
pipelineDescriptor.colorAttachments[0].pixelFormat,
fUniformHandles,
fUniformHandler.fUniforms,
GrMtlBuffer::Create(fGpu,
fUniformHandler.fCurrentGeometryUBOOffset,
kVertex_GrBufferType,
kStatic_GrAccessPattern),
GrMtlBuffer::Create(fGpu,
fUniformHandler.fCurrentFragmentUBOOffset,
kVertex_GrBufferType,
kStatic_GrAccessPattern));
kStatic_GrAccessPattern),
(uint32_t)fUniformHandler.numSamplers(),
std::move(fGeometryProcessor),
std::move(fXferProcessor),
std::move(fFragmentProcessors),
fFragmentProcessorCnt);
}

0 comments on commit 6ed6396

Please sign in to comment.