/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMtlPipelineState_DEFINED
#define GrMtlPipelineState_DEFINED
#include "GrMtlBuffer.h"
#include "GrMtlPipelineStateDataManager.h"
#include "GrStencilSettings.h"
#include "GrTypesPriv.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:
using UniformInfoArray = GrMtlPipelineStateDataManager::UniformInfoArray;
using UniformHandle = GrGLSLProgramDataManager::UniformHandle;
GrMtlPipelineState(
GrMtlGpu* gpu,
id<MTLRenderPipelineState> pipelineState,
MTLPixelFormat pixelFormat,
const GrGLSLBuiltinUniformHandles& builtinUniformHandles,
const UniformInfoArray& uniforms,
sk_sp<GrMtlBuffer> geometryUniformBuffer,
sk_sp<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 GrRenderTarget*, GrSurfaceOrigin,
const GrPrimitiveProcessor& primPRoc, const GrPipeline& pipeline,
const GrTextureProxy* const primProcTextures[]);
void bind(id<MTLRenderCommandEncoder>);
void setBlendConstants(id<MTLRenderCommandEncoder>, GrPixelConfig, const GrXferProcessor&);
void setDepthStencilState(id<MTLRenderCommandEncoder> renderCmdEncoder);
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 GrRenderTarget*, GrSurfaceOrigin);
struct SamplerBindings {
id<MTLSamplerState> fSampler;
id<MTLTexture> fTexture;
SamplerBindings(const GrSamplerState& state, GrTexture* texture, GrMtlGpu*);
};
GrMtlGpu* fGpu;
id<MTLRenderPipelineState> fPipelineState;
MTLPixelFormat fPixelFormat;
RenderTargetState fRenderTargetState;
GrGLSLBuiltinUniformHandles fBuiltinUniformHandles;
GrStencilSettings fStencil;
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