implemented GrMtlPipelineState for metal gpu backend
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>
This commit is contained in:
parent
7b8875dea7
commit
6ed63968a3
@ -9,10 +9,16 @@
|
||||
#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
|
||||
@ -20,21 +26,97 @@ class GrMtlGpu;
|
||||
*/
|
||||
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; }
|
||||
|
||||
private:
|
||||
GrMtlGpu* fGpu;
|
||||
void setData(const GrPrimitiveProcessor& primPRoc, const GrPipeline& pipeline,
|
||||
const GrTextureProxy* const primProcTextures[]);
|
||||
|
||||
void bind(id<MTLRenderCommandEncoder>);
|
||||
|
||||
private:
|
||||
/**
|
||||
* 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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -359,11 +359,13 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(const GrPrimitiveProcess
|
||||
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,
|
||||
@ -371,5 +373,10 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(const GrPrimitiveProcess
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user