diff --git a/include/gpu/GrDirectContext.h b/include/gpu/GrDirectContext.h index 38051fcbef..45c145cd4b 100644 --- a/include/gpu/GrDirectContext.h +++ b/include/gpu/GrDirectContext.h @@ -94,9 +94,9 @@ public: * Abandons all GPU resources and assumes the underlying backend 3D API context is no longer * usable. Call this if you have lost the associated GPU context, and thus internal texture, * buffer, etc. references/IDs are now invalid. Calling this ensures that the destructors of the - * GrContext and any of its created resource objects will not make backend 3D API calls. Content + * context and any of its created resource objects will not make backend 3D API calls. Content * rendered but not previously flushed may be lost. After this function is called all subsequent - * calls on the GrContext will fail or be no-ops. + * calls on the context will fail or be no-ops. * * The typical use case for this function is that the underlying 3D context was lost and further * API calls may crash. @@ -373,6 +373,118 @@ public: GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const { return INHERITED::defaultBackendFormat(ct, renderable); } + + /** + * The explicitly allocated backend texture API allows clients to use Skia to create backend + * objects outside of Skia proper (i.e., Skia's caching system will not know about them.) + * + * It is the client's responsibility to delete all these objects (using deleteBackendTexture) + * before deleting the context used to create them. If the backend is Vulkan, the textures must + * be deleted before abandoning the context as well. Additionally, clients should only delete + * these objects on the thread for which that context is active. + * + * The client is responsible for ensuring synchronization between different uses + * of the backend object (i.e., wrapping it in a surface, rendering to it, deleting the + * surface, rewrapping it in a image and drawing the image will require explicit + * synchronization on the client's part). + */ + + /** + * If possible, create an uninitialized backend texture. The client should ensure that the + * returned backend texture is valid. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_UNDEFINED. + */ + GrBackendTexture createBackendTexture(int width, int height, + const GrBackendFormat&, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo); + + /** + * If possible, create an uninitialized backend texture. The client should ensure that the + * returned backend texture is valid. + * If successful, the created backend texture will be compatible with the provided + * SkColorType. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_UNDEFINED. + */ + GrBackendTexture createBackendTexture(int width, int height, + SkColorType, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo); + + /** + * If possible, create a backend texture initialized to a particular color. The client should + * ensure that the returned backend texture is valid. The client can pass in a finishedProc + * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The + * client is required to call `submit` to send the upload work to the gpu. The + * finishedProc will always get called even if we failed to create the GrBackendTexture. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createBackendTexture(int width, int height, + const GrBackendFormat&, + const SkColor4f& color, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + /** + * If possible, create a backend texture initialized to a particular color. The client should + * ensure that the returned backend texture is valid. The client can pass in a finishedProc + * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The + * client is required to call `submit` to send the upload work to the gpu. The + * finishedProc will always get called even if we failed to create the GrBackendTexture. + * If successful, the created backend texture will be compatible with the provided + * SkColorType. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createBackendTexture(int width, int height, + SkColorType, + const SkColor4f& color, + GrMipmapped, + GrRenderable, + GrProtected = GrProtected::kNo, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + /** + * If possible, create a backend texture initialized with the provided pixmap data. The client + * should ensure that the returned backend texture is valid. The client can pass in a + * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be + * deleted. The client is required to call `submit` to send the upload work to the gpu. + * The finishedProc will always get called even if we failed to create the GrBackendTexture. + * If successful, the created backend texture will be compatible with the provided + * pixmap(s). Compatible, in this case, means that the backend format will be the result + * of calling defaultBackendFormat on the base pixmap's colortype. The src data can be deleted + * when this call returns. + * If numLevels is 1 a non-mipMapped texture will result. If a mipMapped texture is desired + * the data for all the mipmap levels must be provided. In the mipmapped case all the + * colortypes of the provided pixmaps must be the same. Additionally, all the miplevels + * must be sized correctly (please see SkMipmap::ComputeLevelSize and ComputeLevelCount). + * Note: the pixmap's alphatypes and colorspaces are ignored. + * For the Vulkan backend the layout of the created VkImage will be: + * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + */ + GrBackendTexture createBackendTexture(const SkPixmap srcData[], int numLevels, + GrRenderable, GrProtected, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr); + + // Helper version of above for a single level. + GrBackendTexture createBackendTexture(const SkPixmap& srcData, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc = nullptr, + GrGpuFinishedContext finishedContext = nullptr) { + return this->createBackendTexture(&srcData, 1, renderable, isProtected, finishedProc, + finishedContext); + } protected: GrDirectContext(GrBackendApi backend, const GrContextOptions& options); diff --git a/include/private/GrContext.h b/include/private/GrContext.h index 3da11b03bd..d912f6c50a 100644 --- a/include/private/GrContext.h +++ b/include/private/GrContext.h @@ -57,118 +57,6 @@ class SK_API GrContext : public GrRecordingContext { public: ~GrContext() override; - /** - * The explicitly allocated backend texture API allows clients to use Skia to create backend - * objects outside of Skia proper (i.e., Skia's caching system will not know about them.) - * - * It is the client's responsibility to delete all these objects (using deleteBackendTexture) - * before deleting the GrContext used to create them. If the backend is Vulkan, the textures must - * be deleted before abandoning the GrContext as well. Additionally, clients should only delete - * these objects on the thread for which that GrContext is active. - * - * The client is responsible for ensuring synchronization between different uses - * of the backend object (i.e., wrapping it in a surface, rendering to it, deleting the - * surface, rewrapping it in a image and drawing the image will require explicit - * sychronization on the client's part). - */ - - /** - * If possible, create an uninitialized backend texture. The client should ensure that the - * returned backend texture is valid. - * For the Vulkan backend the layout of the created VkImage will be: - * VK_IMAGE_LAYOUT_UNDEFINED. - */ - GrBackendTexture createBackendTexture(int width, int height, - const GrBackendFormat&, - GrMipmapped, - GrRenderable, - GrProtected = GrProtected::kNo); - - /** - * If possible, create an uninitialized backend texture. The client should ensure that the - * returned backend texture is valid. - * If successful, the created backend texture will be compatible with the provided - * SkColorType. - * For the Vulkan backend the layout of the created VkImage will be: - * VK_IMAGE_LAYOUT_UNDEFINED. - */ - GrBackendTexture createBackendTexture(int width, int height, - SkColorType, - GrMipmapped, - GrRenderable, - GrProtected = GrProtected::kNo); - - /** - * If possible, create a backend texture initialized to a particular color. The client should - * ensure that the returned backend texture is valid. The client can pass in a finishedProc - * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The - * client is required to call GrContext::submit to send the upload work to the gpu. The - * finishedProc will always get called even if we failed to create the GrBackendTexture. - * For the Vulkan backend the layout of the created VkImage will be: - * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - */ - GrBackendTexture createBackendTexture(int width, int height, - const GrBackendFormat&, - const SkColor4f& color, - GrMipmapped, - GrRenderable, - GrProtected = GrProtected::kNo, - GrGpuFinishedProc finishedProc = nullptr, - GrGpuFinishedContext finishedContext = nullptr); - - /** - * If possible, create a backend texture initialized to a particular color. The client should - * ensure that the returned backend texture is valid. The client can pass in a finishedProc - * to be notified when the data has been uploaded by the gpu and the texture can be deleted. The - * client is required to call GrContext::submit to send the upload work to the gpu. The - * finishedProc will always get called even if we failed to create the GrBackendTexture. - * If successful, the created backend texture will be compatible with the provided - * SkColorType. - * For the Vulkan backend the layout of the created VkImage will be: - * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - */ - GrBackendTexture createBackendTexture(int width, int height, - SkColorType, - const SkColor4f& color, - GrMipmapped, - GrRenderable, - GrProtected = GrProtected::kNo, - GrGpuFinishedProc finishedProc = nullptr, - GrGpuFinishedContext finishedContext = nullptr); - - /** - * If possible, create a backend texture initialized with the provided pixmap data. The client - * should ensure that the returned backend texture is valid. The client can pass in a - * finishedProc to be notified when the data has been uploaded by the gpu and the texture can be - * deleted. The client is required to call GrContext::submit to send the upload work to the gpu. - * The finishedProc will always get called even if we failed to create the GrBackendTexture. - * If successful, the created backend texture will be compatible with the provided - * pixmap(s). Compatible, in this case, means that the backend format will be the result - * of calling defaultBackendFormat on the base pixmap's colortype. The src data can be deleted - * when this call returns. - * If numLevels is 1 a non-mipMapped texture will result. If a mipMapped texture is desired - * the data for all the mipmap levels must be provided. In the mipmapped case all the - * colortypes of the provided pixmaps must be the same. Additionally, all the miplevels - * must be sized correctly (please see SkMipmap::ComputeLevelSize and ComputeLevelCount). - * Note: the pixmap's alphatypes and colorspaces are ignored. - * For the Vulkan backend the layout of the created VkImage will be: - * VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL - */ - GrBackendTexture createBackendTexture(const SkPixmap srcData[], int numLevels, - GrRenderable, GrProtected, - GrGpuFinishedProc finishedProc = nullptr, - GrGpuFinishedContext finishedContext = nullptr); - - // Helper version of above for a single level. - GrBackendTexture createBackendTexture(const SkPixmap& srcData, - GrRenderable renderable, - GrProtected isProtected, - GrGpuFinishedProc finishedProc = nullptr, - GrGpuFinishedContext finishedContext = nullptr) { - return this->createBackendTexture(&srcData, 1, renderable, isProtected, finishedProc, - finishedContext); - } - /** * If possible, updates a backend texture to be filled to a particular color. The client should * check the return value to see if the update was successful. The client can pass in a diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 575adf98c8..1d28619ff1 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -39,188 +39,10 @@ #include #include -#define ASSERT_OWNED_PROXY(P) \ - SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this) - -#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) -#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner()) -#define RETURN_IF_ABANDONED if (this->abandoned()) { return; } -#define RETURN_FALSE_IF_ABANDONED if (this->abandoned()) { return false; } -#define RETURN_NULL_IF_ABANDONED if (this->abandoned()) { return nullptr; } - GrContext::GrContext(sk_sp proxy) : INHERITED(std::move(proxy)) { } GrContext::~GrContext() = default; -GrBackendTexture GrContext::createBackendTexture(int width, int height, - const GrBackendFormat& backendFormat, - GrMipmapped mipMapped, - GrRenderable renderable, - GrProtected isProtected) { - TRACE_EVENT0("skia.gpu", TRACE_FUNC); - if (!this->asDirectContext()) { - return GrBackendTexture(); - } - - if (this->abandoned()) { - return GrBackendTexture(); - } - - return fGpu->createBackendTexture({width, height}, backendFormat, renderable, - mipMapped, isProtected); -} - -GrBackendTexture GrContext::createBackendTexture(int width, int height, - SkColorType skColorType, - GrMipmapped mipMapped, - GrRenderable renderable, - GrProtected isProtected) { - if (!this->asDirectContext()) { - return GrBackendTexture(); - } - - if (this->abandoned()) { - return GrBackendTexture(); - } - - const GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); - - return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected); -} - -static GrBackendTexture create_and_update_backend_texture( - GrDirectContext* context, - SkISize dimensions, - const GrBackendFormat& backendFormat, - GrMipmapped mipMapped, - GrRenderable renderable, - GrProtected isProtected, - sk_sp finishedCallback, - const GrGpu::BackendTextureData* data) { - GrGpu* gpu = context->priv().getGpu(); - - GrBackendTexture beTex = gpu->createBackendTexture(dimensions, backendFormat, renderable, - mipMapped, isProtected); - if (!beTex.isValid()) { - return {}; - } - - if (!context->priv().getGpu()->updateBackendTexture(beTex, std::move(finishedCallback), data)) { - context->deleteBackendTexture(beTex); - return {}; - } - return beTex; -} - -GrBackendTexture GrContext::createBackendTexture(int width, int height, - const GrBackendFormat& backendFormat, - const SkColor4f& color, - GrMipmapped mipMapped, - GrRenderable renderable, - GrProtected isProtected, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext) { - sk_sp finishedCallback; - if (finishedProc) { - finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); - } - - TRACE_EVENT0("skia.gpu", TRACE_FUNC); - if (!this->asDirectContext()) { - return {}; - } - - if (this->abandoned()) { - return {}; - } - - GrGpu::BackendTextureData data(color); - return create_and_update_backend_texture(this->asDirectContext(), {width, height}, - backendFormat, mipMapped, renderable, isProtected, - std::move(finishedCallback), &data); -} - -GrBackendTexture GrContext::createBackendTexture(int width, int height, - SkColorType skColorType, - const SkColor4f& color, - GrMipmapped mipMapped, - GrRenderable renderable, - GrProtected isProtected, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext) { - sk_sp finishedCallback; - if (finishedProc) { - finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); - } - - if (!this->asDirectContext()) { - return {}; - } - - if (this->abandoned()) { - return {}; - } - - GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); - if (!format.isValid()) { - return {}; - } - - GrColorType grColorType = SkColorTypeToGrColorType(skColorType); - SkColor4f swizzledColor = this->caps()->getWriteSwizzle(format, grColorType).applyTo(color); - - GrGpu::BackendTextureData data(swizzledColor); - return create_and_update_backend_texture(this->asDirectContext(), {width, height}, format, - mipMapped, renderable, isProtected, - std::move(finishedCallback), &data); -} - -GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int numProvidedLevels, - GrRenderable renderable, GrProtected isProtected, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext) { - TRACE_EVENT0("skia.gpu", TRACE_FUNC); - - sk_sp finishedCallback; - if (finishedProc) { - finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); - } - - if (!this->asDirectContext()) { - return {}; - } - - if (this->abandoned()) { - return {}; - } - - if (!srcData || numProvidedLevels <= 0) { - return {}; - } - - int baseWidth = srcData[0].width(); - int baseHeight = srcData[0].height(); - SkColorType colorType = srcData[0].colorType(); - - GrMipmapped mipMapped = GrMipmapped::kNo; - int numExpectedLevels = 1; - if (numProvidedLevels > 1) { - numExpectedLevels = SkMipmap::ComputeLevelCount(baseWidth, baseHeight) + 1; - mipMapped = GrMipmapped::kYes; - } - - if (numProvidedLevels != numExpectedLevels) { - return {}; - } - - GrBackendFormat backendFormat = this->defaultBackendFormat(colorType, renderable); - - GrGpu::BackendTextureData data(srcData); - return create_and_update_backend_texture(this->asDirectContext(), {baseWidth, baseHeight}, - backendFormat, mipMapped, renderable, isProtected, - std::move(finishedCallback), &data); -} - bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, const SkColor4f& color, GrGpuFinishedProc finishedProc, diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp index 78fa9ab512..ac5722a074 100644 --- a/src/gpu/GrDirectContext.cpp +++ b/src/gpu/GrDirectContext.cpp @@ -449,6 +449,159 @@ size_t GrDirectContext::ComputeImageSize(sk_sp image, GrMipmapped mipMa colorSamplesPerPixel, mipMapped, useNextPow2); } +GrBackendTexture GrDirectContext::createBackendTexture(int width, int height, + const GrBackendFormat& backendFormat, + GrMipmapped mipMapped, + GrRenderable renderable, + GrProtected isProtected) { + TRACE_EVENT0("skia.gpu", TRACE_FUNC); + if (this->abandoned()) { + return GrBackendTexture(); + } + + return fGpu->createBackendTexture({width, height}, backendFormat, renderable, + mipMapped, isProtected); +} + +GrBackendTexture GrDirectContext::createBackendTexture(int width, int height, + SkColorType skColorType, + GrMipmapped mipMapped, + GrRenderable renderable, + GrProtected isProtected) { + if (this->abandoned()) { + return GrBackendTexture(); + } + + const GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); + + return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected); +} + +static GrBackendTexture create_and_update_backend_texture( + GrDirectContext* dContext, + SkISize dimensions, + const GrBackendFormat& backendFormat, + GrMipmapped mipMapped, + GrRenderable renderable, + GrProtected isProtected, + sk_sp finishedCallback, + const GrGpu::BackendTextureData* data) { + GrGpu* gpu = dContext->priv().getGpu(); + + GrBackendTexture beTex = gpu->createBackendTexture(dimensions, backendFormat, renderable, + mipMapped, isProtected); + if (!beTex.isValid()) { + return {}; + } + + if (!dContext->priv().getGpu()->updateBackendTexture(beTex, + std::move(finishedCallback), + data)) { + dContext->deleteBackendTexture(beTex); + return {}; + } + return beTex; +} + +GrBackendTexture GrDirectContext::createBackendTexture(int width, int height, + const GrBackendFormat& backendFormat, + const SkColor4f& color, + GrMipmapped mipMapped, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext) { + sk_sp finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + + TRACE_EVENT0("skia.gpu", TRACE_FUNC); + if (this->abandoned()) { + return {}; + } + + GrGpu::BackendTextureData data(color); + return create_and_update_backend_texture(this, {width, height}, + backendFormat, mipMapped, renderable, isProtected, + std::move(finishedCallback), &data); +} + +GrBackendTexture GrDirectContext::createBackendTexture(int width, int height, + SkColorType skColorType, + const SkColor4f& color, + GrMipmapped mipMapped, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext) { + sk_sp finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + + if (this->abandoned()) { + return {}; + } + + GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); + if (!format.isValid()) { + return {}; + } + + GrColorType grColorType = SkColorTypeToGrColorType(skColorType); + SkColor4f swizzledColor = this->caps()->getWriteSwizzle(format, grColorType).applyTo(color); + + GrGpu::BackendTextureData data(swizzledColor); + return create_and_update_backend_texture(this, {width, height}, format, + mipMapped, renderable, isProtected, + std::move(finishedCallback), &data); +} + +GrBackendTexture GrDirectContext::createBackendTexture(const SkPixmap srcData[], + int numProvidedLevels, + GrRenderable renderable, + GrProtected isProtected, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext) { + TRACE_EVENT0("skia.gpu", TRACE_FUNC); + + sk_sp finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + + if (this->abandoned()) { + return {}; + } + + if (!srcData || numProvidedLevels <= 0) { + return {}; + } + + int baseWidth = srcData[0].width(); + int baseHeight = srcData[0].height(); + SkColorType colorType = srcData[0].colorType(); + + GrMipmapped mipMapped = GrMipmapped::kNo; + int numExpectedLevels = 1; + if (numProvidedLevels > 1) { + numExpectedLevels = SkMipmap::ComputeLevelCount(baseWidth, baseHeight) + 1; + mipMapped = GrMipmapped::kYes; + } + + if (numProvidedLevels != numExpectedLevels) { + return {}; + } + + GrBackendFormat backendFormat = this->defaultBackendFormat(colorType, renderable); + + GrGpu::BackendTextureData data(srcData); + return create_and_update_backend_texture(this, {baseWidth, baseHeight}, + backendFormat, mipMapped, renderable, isProtected, + std::move(finishedCallback), &data); +} + #ifdef SK_GL /*************************************************************************************************/