blob: 7271ee7672c8dabc30d96459aa3bcd149e30bfb4 [file] [log] [blame]
* 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 GrMtlResourceProvider_DEFINED
#define GrMtlResourceProvider_DEFINED
#include "include/private/SkSpinlock.h"
#include "include/private/SkTArray.h"
#include "src/core/SkLRUCache.h"
#include "src/gpu/mtl/GrMtlDepthStencil.h"
#include "src/gpu/mtl/GrMtlPipelineStateBuilder.h"
#include "src/gpu/mtl/GrMtlSampler.h"
#import <metal/metal.h>
class GrMtlGpu;
class GrMtlCommandBuffer;
class GrMtlResourceProvider {
GrMtlResourceProvider(GrMtlGpu* gpu);
GrMtlPipelineState* findOrCreateCompatiblePipelineState(
GrRenderTarget*, GrSurfaceOrigin,
const GrPipeline&,
const GrPrimitiveProcessor&,
const GrTextureProxy* const primProcProxies[],
// Finds or creates a compatible MTLDepthStencilState based on the GrStencilSettings.
GrMtlDepthStencil* findOrCreateCompatibleDepthStencilState(const GrStencilSettings&,
// Finds or creates a compatible MTLSamplerState based on the GrSamplerState.
GrMtlSampler* findOrCreateCompatibleSampler(const GrSamplerState&, uint32_t maxMipLevel);
id<MTLBuffer> getDynamicBuffer(size_t size, size_t* offset);
void addBufferCompletionHandler(GrMtlCommandBuffer* cmdBuffer);
// Destroy any cached resources. To be called before releasing the MtlDevice.
void destroyResources();
#ifdef SK_DEBUG
class PipelineStateCache : public ::SkNoncopyable {
PipelineStateCache(GrMtlGpu* gpu);
void release();
GrMtlPipelineState* refPipelineState(GrRenderTarget*, GrSurfaceOrigin,
const GrPrimitiveProcessor&,
const GrTextureProxy* const primProcProxies[],
const GrPipeline&,
enum {
// We may actually have kMaxEntries+1 PipelineStates in context because we create a new
// PipelineState before evicting from the cache.
kMaxEntries = 128,
struct Entry;
struct DescHash {
uint32_t operator()(const GrProgramDesc& desc) const {
return SkOpts::hash_fn(desc.asKey(), desc.keyLength(), 0);
SkLRUCache<const GrMtlPipelineStateBuilder::Desc, std::unique_ptr<Entry>, DescHash> fMap;
GrMtlGpu* fGpu;
int fTotalRequests;
int fCacheMisses;
// Buffer allocator
class BufferSuballocator : public SkRefCnt {
BufferSuballocator(id<MTLDevice> device, size_t size);
~BufferSuballocator() {
fBuffer = nil;
fTotalSize = 0;
id<MTLBuffer> getAllocation(size_t size, size_t* offset);
void addCompletionHandler(GrMtlCommandBuffer* cmdBuffer);
size_t size() { return fTotalSize; }
id<MTLBuffer> fBuffer;
size_t fTotalSize;
size_t fHead; // where we start allocating
size_t fTail; // where we start deallocating
SkSpinlock fMutex;
GrMtlGpu* fGpu;
// Cache of GrMtlPipelineStates
std::unique_ptr<PipelineStateCache> fPipelineStateCache;
SkTDynamicHash<GrMtlSampler, GrMtlSampler::Key> fSamplers;
SkTDynamicHash<GrMtlDepthStencil, GrMtlDepthStencil::Key> fDepthStencilStates;
// This is ref-counted because we might delete the GrContext before the command buffer
// finishes. The completion handler will retain a reference to this so it won't get
// deleted along with the GrContext.
sk_sp<BufferSuballocator> fBufferSuballocator;