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 "GrBackendSurface.h" 11 #include "GrContextPriv.h" 12 #include "GrRenderTargetContextPriv.h" 13 #include "GrTexture.h" 14 15 #include "SkCanvas.h" 16 #include "SkColorSpace_Base.h" 17 #include "SkGpuDevice.h" 18 #include "SkImage_Base.h" 19 #include "SkImage_Gpu.h" 20 #include "SkImagePriv.h" 21 #include "SkSurface_Base.h" 22 23 #if SK_SUPPORT_GPU 24 25 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device) 26 : INHERITED(device->width(), device->height(), &device->surfaceProps()) 27 , fDevice(std::move(device)) { 28 SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact()); 29 } 30 31 SkSurface_Gpu::~SkSurface_Gpu() { 32 } 33 34 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface, 35 SkSurface::BackendHandleAccess access) { 36 switch (access) { 37 case SkSurface::kFlushRead_BackendHandleAccess: 38 break; 39 case SkSurface::kFlushWrite_BackendHandleAccess: 40 case SkSurface::kDiscardWrite_BackendHandleAccess: 41 // for now we don't special-case on Discard, but we may in the future. 42 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode); 43 break; 44 } 45 46 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in. 47 surface->getDevice()->flush(); 48 GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext(); 49 return rtc->accessRenderTarget(); 50 } 51 52 GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) { 53 GrRenderTarget* rt = prepare_rt_for_external_access(this, access); 54 if (!rt) { 55 return 0; 56 } 57 GrTexture* texture = rt->asTexture(); 58 if (texture) { 59 return texture->getTextureHandle(); 60 } 61 return 0; 62 } 63 64 bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) { 65 GrRenderTarget* rt = prepare_rt_for_external_access(this, access); 66 if (!rt) { 67 return false; 68 } 69 *obj = rt->getRenderTargetHandle(); 70 return true; 71 } 72 73 SkCanvas* SkSurface_Gpu::onNewCanvas() { 74 SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags; 75 flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag); 76 77 return new SkCanvas(fDevice.get(), flags); 78 } 79 80 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) { 81 int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples(); 82 GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin(); 83 // TODO: Make caller specify this (change virtual signature of onNewSurface). 84 static const SkBudgeted kBudgeted = SkBudgeted::kNo; 85 return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount, 86 origin, &this->props()); 87 } 88 89 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() { 90 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext(); 91 if (!rtc) { 92 return nullptr; 93 } 94 95 GrContext* ctx = fDevice->context(); 96 97 if (!rtc->asSurfaceProxy()) { 98 return nullptr; 99 } 100 101 SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted(); 102 103 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef(); 104 // If the original render target is a buffer originally created by the client, then we don't 105 // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid 106 // copy-on-write. 107 if (!srcProxy || rtc->priv().refsWrappedObjects()) { 108 SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin()); 109 110 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), budgeted); 111 } 112 113 const SkImageInfo info = fDevice->imageInfo(); 114 sk_sp<SkImage> image; 115 if (srcProxy) { 116 // The renderTargetContext coming out of SkGpuDevice should always be exact and the 117 // above copy creates a kExact surfaceContext. 118 SkASSERT(srcProxy->priv().isExact()); 119 image = sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID, 120 info.alphaType(), std::move(srcProxy), 121 info.refColorSpace(), budgeted); 122 } 123 return image; 124 } 125 126 // Create a new render target and, if necessary, copy the contents of the old 127 // render target into it. Note that this flushes the SkGpuDevice but 128 // doesn't force an OpenGL flush. 129 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { 130 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext(); 131 132 // are we sharing our backing proxy with the image? Note this call should never create a new 133 // image because onCopyOnWrite is only called when there is a cached image. 134 sk_sp<SkImage> image(this->refCachedImage()); 135 SkASSERT(image); 136 137 GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy(); 138 SkASSERT(imageProxy); 139 140 if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) { 141 fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode); 142 } else if (kDiscard_ContentChangeMode == mode) { 143 this->SkSurface_Gpu::onDiscard(); 144 } 145 } 146 147 void SkSurface_Gpu::onDiscard() { 148 fDevice->accessRenderTargetContext()->discard(); 149 } 150 151 bool SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) { 152 return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores); 153 } 154 155 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) { 156 return fDevice->wait(numSemaphores, waitSemaphores); 157 } 158 159 /////////////////////////////////////////////////////////////////////////////// 160 161 bool SkSurface_Gpu::Valid(const SkImageInfo& info) { 162 switch (info.colorType()) { 163 case kRGBA_F16_SkColorType: 164 return info.colorSpace() && info.colorSpace()->gammaIsLinear(); 165 case kRGBA_8888_SkColorType: 166 case kBGRA_8888_SkColorType: 167 return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB(); 168 default: 169 return !info.colorSpace(); 170 } 171 } 172 173 bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) { 174 switch (config) { 175 case kRGBA_half_GrPixelConfig: 176 return colorSpace && colorSpace->gammaIsLinear(); 177 case kSRGBA_8888_GrPixelConfig: 178 case kSBGRA_8888_GrPixelConfig: 179 return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB(); 180 case kRGBA_8888_GrPixelConfig: 181 case kBGRA_8888_GrPixelConfig: 182 // If we don't have sRGB support, we may get here with a color space. It still needs 183 // to be sRGB-like (so that the application will work correctly on sRGB devices.) 184 return !colorSpace || 185 (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport()); 186 default: 187 return !colorSpace; 188 } 189 } 190 191 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted, 192 const SkImageInfo& info, int sampleCount, 193 GrSurfaceOrigin origin, const SkSurfaceProps* props) { 194 if (!SkSurface_Gpu::Valid(info)) { 195 return nullptr; 196 } 197 198 sk_sp<SkGpuDevice> device(SkGpuDevice::Make( 199 ctx, budgeted, info, sampleCount, origin, props, SkGpuDevice::kClear_InitContents)); 200 if (!device) { 201 return nullptr; 202 } 203 return sk_make_sp<SkSurface_Gpu>(std::move(device)); 204 } 205 206 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, 207 const GrBackendTextureDesc& desc, 208 sk_sp<SkColorSpace> colorSpace, 209 const SkSurfaceProps* props) { 210 if (!context) { 211 return nullptr; 212 } 213 GrBackendTexture tex(desc, context->contextPriv().getBackend()); 214 return MakeFromBackendTexture(context, tex, desc.fOrigin, desc.fSampleCnt, colorSpace, props); 215 } 216 217 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex, 218 GrSurfaceOrigin origin, int sampleCnt, 219 sk_sp<SkColorSpace> colorSpace, 220 const SkSurfaceProps* props) { 221 if (!context) { 222 return nullptr; 223 } 224 if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) { 225 return nullptr; 226 } 227 228 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext( 229 tex, 230 origin, 231 sampleCnt, 232 std::move(colorSpace), 233 props)); 234 if (!rtc) { 235 return nullptr; 236 } 237 238 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(), 239 SkGpuDevice::kUninit_InitContents)); 240 if (!device) { 241 return nullptr; 242 } 243 return sk_make_sp<SkSurface_Gpu>(std::move(device)); 244 } 245 246 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context, 247 const GrBackendRenderTargetDesc& desc, 248 sk_sp<SkColorSpace> colorSpace, 249 const SkSurfaceProps* props) { 250 if (!context) { 251 return nullptr; 252 } 253 254 GrBackendRenderTarget backendRT(desc, context->contextPriv().getBackend()); 255 return MakeFromBackendRenderTarget(context, backendRT, desc.fOrigin, 256 std::move(colorSpace), props); 257 258 } 259 260 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context, 261 const GrBackendRenderTarget& backendRT, 262 GrSurfaceOrigin origin, 263 sk_sp<SkColorSpace> colorSpace, 264 const SkSurfaceProps* props) { 265 if (!context) { 266 return nullptr; 267 } 268 if (!SkSurface_Gpu::Valid(context, backendRT.config(), colorSpace.get())) { 269 return nullptr; 270 } 271 272 sk_sp<GrRenderTargetContext> rtc( 273 context->contextPriv().makeBackendRenderTargetRenderTargetContext(backendRT, 274 origin, 275 std::move(colorSpace), 276 props)); 277 if (!rtc) { 278 return nullptr; 279 } 280 281 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), 282 backendRT.width(), backendRT.height(), 283 SkGpuDevice::kUninit_InitContents)); 284 if (!device) { 285 return nullptr; 286 } 287 288 return sk_make_sp<SkSurface_Gpu>(std::move(device)); 289 } 290 291 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context, 292 const GrBackendTextureDesc& desc, 293 sk_sp<SkColorSpace> colorSpace, 294 const SkSurfaceProps* props) { 295 if (!context) { 296 return nullptr; 297 } 298 GrBackendTexture tex(desc, context->contextPriv().getBackend()); 299 return MakeFromBackendTextureAsRenderTarget(context, tex, desc.fOrigin, desc.fSampleCnt, 300 std::move(colorSpace), props); 301 } 302 303 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context, 304 const GrBackendTexture& tex, 305 GrSurfaceOrigin origin, 306 int sampleCnt, 307 sk_sp<SkColorSpace> colorSpace, 308 const SkSurfaceProps* props) { 309 if (!context) { 310 return nullptr; 311 } 312 if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) { 313 return nullptr; 314 } 315 316 sk_sp<GrRenderTargetContext> rtc( 317 context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext( 318 tex, 319 origin, 320 sampleCnt, 321 std::move(colorSpace), 322 props)); 323 if (!rtc) { 324 return nullptr; 325 } 326 327 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(), 328 SkGpuDevice::kUninit_InitContents)); 329 if (!device) { 330 return nullptr; 331 } 332 return sk_make_sp<SkSurface_Gpu>(std::move(device)); 333 } 334 335 #endif 336