1 /*
2 * Copyright 2012 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 "SkSurface_Gpu.h"
9
10 #include "GrResourceProvider.h"
11 #include "SkCanvas.h"
12 #include "SkGpuDevice.h"
13 #include "SkImage_Base.h"
14 #include "SkImage_Gpu.h"
15 #include "SkImagePriv.h"
16 #include "SkSurface_Base.h"
17
18 #if SK_SUPPORT_GPU
19
SkSurface_Gpu(SkGpuDevice * device)20 SkSurface_Gpu::SkSurface_Gpu(SkGpuDevice* device)
21 : INHERITED(device->width(), device->height(), &device->surfaceProps())
22 , fDevice(SkRef(device)) {
23 }
24
~SkSurface_Gpu()25 SkSurface_Gpu::~SkSurface_Gpu() {
26 fDevice->unref();
27 }
28
prepare_rt_for_external_access(SkSurface_Gpu * surface,SkSurface::BackendHandleAccess access)29 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
30 SkSurface::BackendHandleAccess access) {
31 switch (access) {
32 case SkSurface::kFlushRead_BackendHandleAccess:
33 break;
34 case SkSurface::kFlushWrite_BackendHandleAccess:
35 case SkSurface::kDiscardWrite_BackendHandleAccess:
36 // for now we don't special-case on Discard, but we may in the future.
37 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
38 // legacy: need to dirty the bitmap's genID in our device (curse it)
39 surface->getDevice()->accessBitmap(false).notifyPixelsChanged();
40 break;
41 }
42
43 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
44 GrRenderTarget* rt = surface->getDevice()->accessRenderTarget();
45 rt->prepareForExternalIO();
46 return rt;
47 }
48
onGetTextureHandle(BackendHandleAccess access)49 GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
50 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
51 GrTexture* texture = rt->asTexture();
52 if (texture) {
53 return texture->getTextureHandle();
54 }
55 return 0;
56 }
57
onGetRenderTargetHandle(GrBackendObject * obj,BackendHandleAccess access)58 bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
59 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
60 *obj = rt->getRenderTargetHandle();
61 return true;
62 }
63
onNewCanvas()64 SkCanvas* SkSurface_Gpu::onNewCanvas() {
65 SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
66 flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
67
68 return new SkCanvas(fDevice, flags);
69 }
70
onNewSurface(const SkImageInfo & info)71 SkSurface* SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
72 GrRenderTarget* rt = fDevice->accessRenderTarget();
73 int sampleCount = rt->numColorSamples();
74 // TODO: Make caller specify this (change virtual signature of onNewSurface).
75 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
76 return SkSurface::NewRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
77 &this->props());
78 }
79
onNewImageSnapshot(SkBudgeted budgeted,ForceCopyMode forceCopyMode)80 SkImage* SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, ForceCopyMode forceCopyMode) {
81 GrRenderTarget* rt = fDevice->accessRenderTarget();
82 SkASSERT(rt);
83 GrTexture* tex = rt->asTexture();
84 SkAutoTUnref<GrTexture> copy;
85 // TODO: Force a copy when the rt is an external resource.
86 if (kYes_ForceCopyMode == forceCopyMode || !tex) {
87 GrSurfaceDesc desc = fDevice->accessRenderTarget()->desc();
88 GrContext* ctx = fDevice->context();
89 desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag;
90 copy.reset(ctx->textureProvider()->createTexture(desc, budgeted));
91 if (!copy) {
92 return nullptr;
93 }
94 if (!ctx->copySurface(copy, rt)) {
95 return nullptr;
96 }
97 tex = copy;
98 }
99 const SkImageInfo info = fDevice->imageInfo();
100 SkImage* image = nullptr;
101 if (tex) {
102 image = new SkImage_Gpu(info.width(), info.height(), kNeedNewImageUniqueID,
103 info.alphaType(), tex, budgeted);
104 }
105 return image;
106 }
107
108 // Create a new render target and, if necessary, copy the contents of the old
109 // render target into it. Note that this flushes the SkGpuDevice but
110 // doesn't force an OpenGL flush.
onCopyOnWrite(ContentChangeMode mode)111 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
112 GrRenderTarget* rt = fDevice->accessRenderTarget();
113 // are we sharing our render target with the image? Note this call should never create a new
114 // image because onCopyOnWrite is only called when there is a cached image.
115 SkAutoTUnref<SkImage> image(this->refCachedImage(SkBudgeted::kNo, kNo_ForceUnique));
116 SkASSERT(image);
117 if (rt->asTexture() == as_IB(image)->getTexture()) {
118 this->fDevice->replaceRenderTarget(SkSurface::kRetain_ContentChangeMode == mode);
119 SkTextureImageApplyBudgetedDecision(image);
120 } else if (kDiscard_ContentChangeMode == mode) {
121 this->SkSurface_Gpu::onDiscard();
122 }
123 }
124
onDiscard()125 void SkSurface_Gpu::onDiscard() {
126 fDevice->accessRenderTarget()->discard();
127 }
128
onPrepareForExternalIO()129 void SkSurface_Gpu::onPrepareForExternalIO() {
130 fDevice->accessRenderTarget()->prepareForExternalIO();
131 }
132
133 ///////////////////////////////////////////////////////////////////////////////
134
NewRenderTargetDirect(GrRenderTarget * target,const SkSurfaceProps * props)135 SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, const SkSurfaceProps* props) {
136 SkAutoTUnref<SkGpuDevice> device(
137 SkGpuDevice::Create(target, props, SkGpuDevice::kUninit_InitContents));
138 if (!device) {
139 return nullptr;
140 }
141 return new SkSurface_Gpu(device);
142 }
143
NewRenderTarget(GrContext * ctx,SkBudgeted budgeted,const SkImageInfo & info,int sampleCount,const SkSurfaceProps * props,GrTextureStorageAllocator customAllocator)144 SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, SkBudgeted budgeted, const SkImageInfo& info,
145 int sampleCount, const SkSurfaceProps* props,
146 GrTextureStorageAllocator customAllocator) {
147 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(
148 ctx, budgeted, info, sampleCount, props, SkGpuDevice::kClear_InitContents,
149 customAllocator));
150 if (!device) {
151 return nullptr;
152 }
153 return new SkSurface_Gpu(device);
154 }
155
NewFromBackendTexture(GrContext * context,const GrBackendTextureDesc & desc,const SkSurfaceProps * props)156 SkSurface* SkSurface::NewFromBackendTexture(GrContext* context, const GrBackendTextureDesc& desc,
157 const SkSurfaceProps* props) {
158 if (nullptr == context) {
159 return nullptr;
160 }
161 if (!SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag)) {
162 return nullptr;
163 }
164 SkAutoTUnref<GrSurface> surface(context->textureProvider()->wrapBackendTexture(desc,
165 kBorrow_GrWrapOwnership));
166 if (!surface) {
167 return nullptr;
168 }
169 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(surface->asRenderTarget(), props,
170 SkGpuDevice::kUninit_InitContents));
171 if (!device) {
172 return nullptr;
173 }
174 return new SkSurface_Gpu(device);
175 }
176
NewFromBackendRenderTarget(GrContext * context,const GrBackendRenderTargetDesc & desc,const SkSurfaceProps * props)177 SkSurface* SkSurface::NewFromBackendRenderTarget(GrContext* context,
178 const GrBackendRenderTargetDesc& desc,
179 const SkSurfaceProps* props) {
180 if (nullptr == context) {
181 return nullptr;
182 }
183 SkAutoTUnref<GrRenderTarget> rt(context->textureProvider()->wrapBackendRenderTarget(desc));
184 if (!rt) {
185 return nullptr;
186 }
187 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(rt, props,
188 SkGpuDevice::kUninit_InitContents));
189 if (!device) {
190 return nullptr;
191 }
192 return new SkSurface_Gpu(device);
193 }
194
NewFromBackendTextureAsRenderTarget(GrContext * context,const GrBackendTextureDesc & desc,const SkSurfaceProps * props)195 SkSurface* SkSurface::NewFromBackendTextureAsRenderTarget(GrContext* context,
196 const GrBackendTextureDesc& desc,
197 const SkSurfaceProps* props) {
198 if (nullptr == context) {
199 return nullptr;
200 }
201 SkAutoTUnref<GrRenderTarget> rt(
202 context->resourceProvider()->wrapBackendTextureAsRenderTarget(desc));
203 if (!rt) {
204 return nullptr;
205 }
206 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(rt, props,
207 SkGpuDevice::kUninit_InitContents));
208 if (!device) {
209 return nullptr;
210 }
211 return new SkSurface_Gpu(device);
212 }
213
214 #endif
215