1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrResourceProvider.h" 9 10#include "GrGpu.h" 11#include "GrIndexBuffer.h" 12#include "GrPathRendering.h" 13#include "GrRenderTarget.h" 14#include "GrRenderTargetPriv.h" 15#include "GrResourceCache.h" 16#include "GrResourceKey.h" 17#include "GrStencilAttachment.h" 18#include "GrVertexBuffer.h" 19 20GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); 21 22GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner) 23 : INHERITED(gpu, cache, owner) { 24 GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey); 25 fQuadIndexBufferKey = gQuadIndexBufferKey; 26} 27 28const GrIndexBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern, 29 int patternSize, 30 int reps, 31 int vertCount, 32 const GrUniqueKey& key) { 33 size_t bufferSize = patternSize * reps * sizeof(uint16_t); 34 35 // This is typically used in GrBatchs, so we assume kNoPendingIO. 36 GrIndexBuffer* buffer = this->createIndexBuffer(bufferSize, kStatic_BufferUsage, 37 kNoPendingIO_Flag); 38 if (!buffer) { 39 return nullptr; 40 } 41 uint16_t* data = (uint16_t*) buffer->map(); 42 bool useTempData = (nullptr == data); 43 if (useTempData) { 44 data = new uint16_t[reps * patternSize]; 45 } 46 for (int i = 0; i < reps; ++i) { 47 int baseIdx = i * patternSize; 48 uint16_t baseVert = (uint16_t)(i * vertCount); 49 for (int j = 0; j < patternSize; ++j) { 50 data[baseIdx+j] = baseVert + pattern[j]; 51 } 52 } 53 if (useTempData) { 54 if (!buffer->updateData(data, bufferSize)) { 55 buffer->unref(); 56 return nullptr; 57 } 58 delete[] data; 59 } else { 60 buffer->unmap(); 61 } 62 this->assignUniqueKeyToResource(key, buffer); 63 return buffer; 64} 65 66const GrIndexBuffer* GrResourceProvider::createQuadIndexBuffer() { 67 static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1; 68 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535); 69 static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 }; 70 71 return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey); 72} 73 74GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStrokeInfo& stroke) { 75 SkASSERT(this->gpu()->pathRendering()); 76 return this->gpu()->pathRendering()->createPath(path, stroke); 77} 78 79GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen, 80 const GrStrokeInfo& stroke) { 81 SkASSERT(this->gpu()->pathRendering()); 82 return this->gpu()->pathRendering()->createPathRange(gen, stroke); 83} 84 85GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf, const SkDescriptor* desc, 86 const GrStrokeInfo& stroke) { 87 88 SkASSERT(this->gpu()->pathRendering()); 89 return this->gpu()->pathRendering()->createGlyphs(tf, desc, stroke); 90} 91 92GrIndexBuffer* GrResourceProvider::createIndexBuffer(size_t size, BufferUsage usage, 93 uint32_t flags) { 94 if (this->isAbandoned()) { 95 return nullptr; 96 } 97 98 bool noPendingIO = SkToBool(flags & kNoPendingIO_Flag); 99 bool dynamic = kDynamic_BufferUsage == usage; 100 if (dynamic) { 101 // bin by pow2 with a reasonable min 102 static const uint32_t MIN_SIZE = 1 << 12; 103 size = SkTMax(MIN_SIZE, GrNextPow2(SkToUInt(size))); 104 105 GrScratchKey key; 106 GrIndexBuffer::ComputeScratchKey(size, true, &key); 107 uint32_t scratchFlags = 0; 108 if (noPendingIO) { 109 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; 110 } else { 111 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; 112 } 113 GrGpuResource* resource = this->cache()->findAndRefScratchResource(key, size, scratchFlags); 114 if (resource) { 115 return static_cast<GrIndexBuffer*>(resource); 116 } 117 } 118 return this->gpu()->createIndexBuffer(size, dynamic); 119} 120 121GrVertexBuffer* GrResourceProvider::createVertexBuffer(size_t size, BufferUsage usage, 122 uint32_t flags) { 123 if (this->isAbandoned()) { 124 return nullptr; 125 } 126 127 bool noPendingIO = SkToBool(flags & kNoPendingIO_Flag); 128 bool dynamic = kDynamic_BufferUsage == usage; 129 if (dynamic) { 130 // bin by pow2 with a reasonable min 131 static const uint32_t MIN_SIZE = 1 << 12; 132 size = SkTMax(MIN_SIZE, GrNextPow2(SkToUInt(size))); 133 134 GrScratchKey key; 135 GrVertexBuffer::ComputeScratchKey(size, true, &key); 136 uint32_t scratchFlags = 0; 137 if (noPendingIO) { 138 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag; 139 } else { 140 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag; 141 } 142 GrGpuResource* resource = this->cache()->findAndRefScratchResource(key, size, scratchFlags); 143 if (resource) { 144 return static_cast<GrVertexBuffer*>(resource); 145 } 146 } 147 return this->gpu()->createVertexBuffer(size, dynamic); 148} 149 150GrTransferBuffer* GrResourceProvider::createTransferBuffer(size_t size, TransferType type, 151 uint32_t flags) { 152 if (this->isAbandoned()) { 153 return nullptr; 154 } 155 156 //bool noPendingIO = SkToBool(flags & kNoPendingIO_Flag); 157 return this->gpu()->createTransferBuffer(size, type); 158} 159 160GrBatchAtlas* GrResourceProvider::createAtlas(GrPixelConfig config, 161 int width, int height, 162 int numPlotsX, int numPlotsY, 163 GrBatchAtlas::EvictionFunc func, void* data) { 164 GrSurfaceDesc desc; 165 desc.fFlags = kNone_GrSurfaceFlags; 166 desc.fWidth = width; 167 desc.fHeight = height; 168 desc.fConfig = config; 169 170 // We don't want to flush the context so we claim we're in the middle of flushing so as to 171 // guarantee we do not recieve a texture with pending IO 172 // TODO: Determine how to avoid having to do this. (https://bug.skia.org/4156) 173 static const uint32_t kFlags = GrResourceProvider::kNoPendingIO_Flag; 174 GrTexture* texture = this->createApproxTexture(desc, kFlags); 175 if (!texture) { 176 return nullptr; 177 } 178 GrBatchAtlas* atlas = new GrBatchAtlas(texture, numPlotsX, numPlotsY); 179 atlas->registerEvictionCallback(func, data); 180 return atlas; 181} 182 183GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) { 184 SkASSERT(rt); 185 if (rt->renderTargetPriv().getStencilAttachment()) { 186 return rt->renderTargetPriv().getStencilAttachment(); 187 } 188 189 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) { 190 GrUniqueKey sbKey; 191 192 int width = rt->width(); 193 int height = rt->height(); 194#if 0 195 if (this->caps()->oversizedStencilSupport()) { 196 width = SkNextPow2(width); 197 height = SkNextPow2(height); 198 } 199#endif 200 bool newStencil = false; 201 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height, 202 rt->numStencilSamples(), &sbKey); 203 GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>( 204 this->findAndRefResourceByUniqueKey(sbKey)); 205 if (!stencil) { 206 // Need to try and create a new stencil 207 stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height); 208 if (stencil) { 209 stencil->resourcePriv().setUniqueKey(sbKey); 210 newStencil = true; 211 } 212 } 213 if (rt->renderTargetPriv().attachStencilAttachment(stencil)) { 214 if (newStencil) { 215 // Right now we're clearing the stencil attachment here after it is 216 // attached to a RT for the first time. When we start matching 217 // stencil buffers with smaller color targets this will no longer 218 // be correct because it won't be guaranteed to clear the entire 219 // sb. 220 // We used to clear down in the GL subclass using a special purpose 221 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported 222 // FBO status. 223 this->gpu()->clearStencil(rt); 224 } 225 } 226 } 227 return rt->renderTargetPriv().getStencilAttachment(); 228} 229 230GrRenderTarget* GrResourceProvider::wrapBackendTextureAsRenderTarget( 231 const GrBackendTextureDesc& desc, GrWrapOwnership ownership) { 232 if (this->isAbandoned()) { 233 return nullptr; 234 } 235 return this->gpu()->wrapBackendTextureAsRenderTarget(desc, ownership); 236} 237 238