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