blob: 60cbf9c8963245865aa7e1cc0f629dee62fe5184 [file] [log] [blame]
Brian Osman13dddce2017-05-09 13:19:50 -04001/*
2 * Copyright 2017 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 "GrBackendTextureImageGenerator.h"
9
10#include "GrContext.h"
11#include "GrContextPriv.h"
Robert Phillips646e4292017-06-13 12:44:56 -040012#include "GrGpu.h"
Greg Danielb8ad00b2017-10-18 16:34:16 -040013#include "GrRenderTargetContext.h"
Brian Osman13dddce2017-05-09 13:19:50 -040014#include "GrResourceCache.h"
15#include "GrResourceProvider.h"
16#include "GrSemaphore.h"
Robert Phillips646e4292017-06-13 12:44:56 -040017#include "GrTexture.h"
Greg Danielb8ad00b2017-10-18 16:34:16 -040018#include "GrTexturePriv.h"
Brian Osman13dddce2017-05-09 13:19:50 -040019
20#include "SkGr.h"
21#include "SkMessageBus.h"
22
23GrBackendTextureImageGenerator::RefHelper::~RefHelper() {
24 SkASSERT(nullptr == fBorrowedTexture);
25 SkASSERT(SK_InvalidGenID == fBorrowingContextID);
26
27 // Generator has been freed, and no one is borrowing the texture. Notify the original cache
28 // that it can free the last ref, so it happens on the correct thread.
29 GrGpuResourceFreedMessage msg { fOriginalTexture, fOwningContextID };
30 SkMessageBus<GrGpuResourceFreedMessage>::Post(msg);
31}
32
33// TODO: I copied this from SkImage_Gpu, perhaps we put a version of this somewhere else?
34static GrBackendTexture make_backend_texture_from_handle(GrBackend backend,
35 int width, int height,
36 GrPixelConfig config,
Greg Danielb8ad00b2017-10-18 16:34:16 -040037 GrMipMapped mipMapped,
Brian Osman13dddce2017-05-09 13:19:50 -040038 GrBackendObject handle) {
Brian Salomon8fe24272017-07-07 12:56:11 -040039 switch (backend) {
40 case kOpenGL_GrBackend: {
41 const GrGLTextureInfo* glInfo = (const GrGLTextureInfo*)(handle);
Greg Danielb8ad00b2017-10-18 16:34:16 -040042 return GrBackendTexture(width, height, config, mipMapped, *glInfo);
Brian Salomon8fe24272017-07-07 12:56:11 -040043 }
Mike Reedd20b5c42017-06-14 06:03:10 -040044#ifdef SK_VULKAN
Brian Salomon8fe24272017-07-07 12:56:11 -040045 case kVulkan_GrBackend: {
46 const GrVkImageInfo* vkInfo = (const GrVkImageInfo*)(handle);
47 return GrBackendTexture(width, height, *vkInfo);
48 }
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +000049#endif
Brian Salomon8fe24272017-07-07 12:56:11 -040050 case kMock_GrBackend: {
51 const GrMockTextureInfo* mockInfo = (const GrMockTextureInfo*)(handle);
Greg Danielb8ad00b2017-10-18 16:34:16 -040052 return GrBackendTexture(width, height, config, mipMapped, *mockInfo);
Brian Salomon8fe24272017-07-07 12:56:11 -040053 }
54 default:
55 return GrBackendTexture();
56 }
Brian Osman13dddce2017-05-09 13:19:50 -040057}
58
59std::unique_ptr<SkImageGenerator>
Robert Phillipsb0e93a22017-08-29 08:26:54 -040060GrBackendTextureImageGenerator::Make(sk_sp<GrTexture> texture, GrSurfaceOrigin origin,
61 sk_sp<GrSemaphore> semaphore,
Brian Osman13dddce2017-05-09 13:19:50 -040062 SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) {
63 if (colorSpace && (!colorSpace->gammaCloseToSRGB() && !colorSpace->gammaIsLinear())) {
64 return nullptr;
65 }
66
67 SkColorType colorType = kUnknown_SkColorType;
68 if (!GrPixelConfigToColorType(texture->config(), &colorType)) {
69 return nullptr;
70 }
71
72 GrContext* context = texture->getContext();
73
74 // Attach our texture to this context's resource cache. This ensures that deletion will happen
75 // in the correct thread/context. This adds the only ref to the texture that will persist from
76 // this point. That ref will be released when the generator's RefHelper is freed.
77 context->getResourceCache()->insertCrossContextGpuResource(texture.get());
78
79 GrBackend backend = context->contextPriv().getBackend();
Greg Danielb8ad00b2017-10-18 16:34:16 -040080 GrMipMapped mipMapped = texture->texturePriv().hasMipMaps() ? GrMipMapped::kYes
81 : GrMipMapped::kNo;
Brian Osman13dddce2017-05-09 13:19:50 -040082 GrBackendTexture backendTexture = make_backend_texture_from_handle(backend,
83 texture->width(),
84 texture->height(),
85 texture->config(),
Greg Danielb8ad00b2017-10-18 16:34:16 -040086 mipMapped,
Brian Osman13dddce2017-05-09 13:19:50 -040087 texture->getTextureHandle());
88
89 SkImageInfo info = SkImageInfo::Make(texture->width(), texture->height(), colorType, alphaType,
90 std::move(colorSpace));
91 return std::unique_ptr<SkImageGenerator>(new GrBackendTextureImageGenerator(
Robert Phillipsb0e93a22017-08-29 08:26:54 -040092 info, texture.get(), origin, context->uniqueID(), std::move(semaphore), backendTexture));
Brian Osman13dddce2017-05-09 13:19:50 -040093}
94
95GrBackendTextureImageGenerator::GrBackendTextureImageGenerator(const SkImageInfo& info,
96 GrTexture* texture,
Robert Phillipsb0e93a22017-08-29 08:26:54 -040097 GrSurfaceOrigin origin,
Brian Osman13dddce2017-05-09 13:19:50 -040098 uint32_t owningContextID,
99 sk_sp<GrSemaphore> semaphore,
100 const GrBackendTexture& backendTex)
101 : INHERITED(info)
102 , fRefHelper(new RefHelper(texture, owningContextID))
103 , fSemaphore(std::move(semaphore))
104 , fLastBorrowingContextID(SK_InvalidGenID)
105 , fBackendTexture(backendTex)
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400106 , fSurfaceOrigin(origin) { }
Brian Osman13dddce2017-05-09 13:19:50 -0400107
108GrBackendTextureImageGenerator::~GrBackendTextureImageGenerator() {
109 fRefHelper->unref();
110}
111
Brian Osman13dddce2017-05-09 13:19:50 -0400112///////////////////////////////////////////////////////////////////////////////////////////////////
113
114#if SK_SUPPORT_GPU
115void GrBackendTextureImageGenerator::ReleaseRefHelper_TextureReleaseProc(void* ctx) {
116 RefHelper* refHelper = static_cast<RefHelper*>(ctx);
117 SkASSERT(refHelper);
118
119 // Release texture so another context can use it
120 refHelper->fBorrowedTexture = nullptr;
121 refHelper->fBorrowingContextID = SK_InvalidGenID;
122 refHelper->unref();
123}
124
Stan Ilievba81af22017-06-08 15:16:53 -0400125sk_sp<GrTextureProxy> GrBackendTextureImageGenerator::onGenerateTexture(
Christopher Cameron77e96662017-07-08 01:47:47 -0700126 GrContext* context, const SkImageInfo& info, const SkIPoint& origin,
Greg Danielf88c12e2017-10-09 09:57:35 -0400127 SkTransferFunctionBehavior, bool willNeedMipMaps) {
Brian Osman13dddce2017-05-09 13:19:50 -0400128 SkASSERT(context);
129
130 if (context->contextPriv().getBackend() != fBackendTexture.backend()) {
131 return nullptr;
132 }
133
134 sk_sp<GrTexture> tex;
135
136 if (fRefHelper->fBorrowingContextID == context->uniqueID()) {
137 // If a client re-draws the same image multiple times, the texture we return will be cached
138 // and re-used. If they draw a subset, though, we may be re-called. In that case, we want
139 // to re-use the borrowed texture we've previously created.
140 tex = sk_ref_sp(fRefHelper->fBorrowedTexture);
141 SkASSERT(tex);
142 } else {
143 // The texture is available or borrwed by another context. Try for exclusive access.
144 uint32_t expectedID = SK_InvalidGenID;
145 if (!fRefHelper->fBorrowingContextID.compare_exchange(&expectedID, context->uniqueID())) {
146 // Some other context is currently borrowing the texture. We aren't allowed to use it.
147 return nullptr;
148 } else {
149 // Wait on a semaphore when a new context has just started borrowing the texture. This
150 // is conservative, but shouldn't be too expensive.
151 if (fSemaphore && fLastBorrowingContextID != context->uniqueID()) {
152 context->getGpu()->waitSemaphore(fSemaphore);
153 fLastBorrowingContextID = context->uniqueID();
154 }
155 }
156
157 // We just gained access to the texture. If we're on the original context, we could use the
158 // original texture, but we'd have no way of detecting that it's no longer in-use. So we
159 // always make a wrapped copy, where the release proc informs us that the context is done
160 // with it. This is unfortunate - we'll have two texture objects referencing the same GPU
161 // object. However, no client can ever see the original texture, so this should be safe.
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400162 tex = context->resourceProvider()->wrapBackendTexture(fBackendTexture,
Brian Osman13dddce2017-05-09 13:19:50 -0400163 kBorrow_GrWrapOwnership);
164 if (!tex) {
165 fRefHelper->fBorrowingContextID = SK_InvalidGenID;
166 return nullptr;
167 }
168 fRefHelper->fBorrowedTexture = tex.get();
169
170 tex->setRelease(ReleaseRefHelper_TextureReleaseProc, fRefHelper);
171 fRefHelper->ref();
172 }
173
174 SkASSERT(fRefHelper->fBorrowingContextID == context->uniqueID());
175
Robert Phillips066f0202017-07-25 10:16:35 -0400176 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeWrapped(std::move(tex), fSurfaceOrigin);
Brian Osman13dddce2017-05-09 13:19:50 -0400177
178 if (0 == origin.fX && 0 == origin.fY &&
Greg Danielb8ad00b2017-10-18 16:34:16 -0400179 info.width() == fBackendTexture.width() && info.height() == fBackendTexture.height() &&
180 (!willNeedMipMaps || proxy->isMipMapped())) {
181 // If the caller wants the entire texture and we have the correct mip support, we're done
Brian Osman13dddce2017-05-09 13:19:50 -0400182 return proxy;
183 } else {
184 // Otherwise, make a copy of the requested subset. Make sure our temporary is renderable,
Greg Danielb8ad00b2017-10-18 16:34:16 -0400185 // because Vulkan will want to do the copy as a draw. All other copies would require a
186 // layout change in Vulkan and we do not change the layout of borrowed images.
187 sk_sp<GrRenderTargetContext> rtContext(context->makeDeferredRenderTargetContext(
188 SkBackingFit::kExact, info.width(), info.height(), proxy->config(), nullptr,
189 0, willNeedMipMaps, proxy->origin(), nullptr, SkBudgeted::kYes));
Brian Salomon63e79732017-05-15 21:23:13 -0400190
Greg Danielb8ad00b2017-10-18 16:34:16 -0400191 if (!rtContext) {
Brian Osman13dddce2017-05-09 13:19:50 -0400192 return nullptr;
193 }
194
195 SkIRect subset = SkIRect::MakeXYWH(origin.fX, origin.fY, info.width(), info.height());
Greg Danielb8ad00b2017-10-18 16:34:16 -0400196 if (!rtContext->copy(proxy.get(), subset, SkIPoint::Make(0, 0))) {
Brian Osman13dddce2017-05-09 13:19:50 -0400197 return nullptr;
198 }
199
Greg Danielb8ad00b2017-10-18 16:34:16 -0400200 return rtContext->asTextureProxyRef();
Brian Osman13dddce2017-05-09 13:19:50 -0400201 }
202}
203#endif