| /* | |
| * Copyright 2016 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SurfaceContext_DEFINED | |
| #define SurfaceContext_DEFINED | |
| #include "include/core/SkImage.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/private/SkDebug.h" | |
| #include "src/gpu/Swizzle.h" | |
| #include "src/gpu/ganesh/GrColorInfo.h" | |
| #include "src/gpu/ganesh/GrGpuBuffer.h" | |
| #include "src/gpu/ganesh/GrImageInfo.h" | |
| #include "src/gpu/ganesh/GrPixmap.h" | |
| #include "src/gpu/ganesh/GrRenderTargetProxy.h" // IWYU pragma: keep | |
| #include "src/gpu/ganesh/GrRenderTask.h" // IWYU pragma: keep | |
| #include "src/gpu/ganesh/GrSamplerState.h" | |
| #include "src/gpu/ganesh/GrSurfaceProxy.h" | |
| #include "src/gpu/ganesh/GrSurfaceProxyView.h" | |
| #include "src/gpu/ganesh/GrTextureProxy.h" // IWYU pragma: keep | |
| #include <cstddef> | |
| #include <functional> | |
| #include <memory> | |
| #include <utility> | |
| class GrCaps; | |
| class GrDirectContext; | |
| class GrDrawingManager; | |
| class GrRecordingContext; | |
| class GrRecordingContextPriv; | |
| class GrTransferFromRenderTask; | |
| class SkColorSpace; | |
| enum GrSurfaceOrigin : int; | |
| enum SkColorType : int; | |
| enum SkYUVColorSpace : int; | |
| enum class GrColorType; | |
| struct SkIPoint; | |
| struct SkImageInfo; | |
| namespace skgpu { | |
| class SingleOwner; | |
| enum class Mipmapped : bool; | |
| } | |
| namespace skgpu::ganesh { | |
| class SurfaceFillContext; | |
| class SurfaceContext { | |
| public: | |
| // If it is known that the GrSurfaceProxy is not renderable, you can directly call the ctor | |
| // here to make a SurfaceContext on the stack. | |
| SurfaceContext(GrRecordingContext*, GrSurfaceProxyView readView, const GrColorInfo&); | |
| virtual ~SurfaceContext() = default; | |
| GrRecordingContext* recordingContext() const { return fContext; } | |
| const GrColorInfo& colorInfo() const { return fColorInfo; } | |
| GrImageInfo imageInfo() const { return {fColorInfo, fReadView.proxy()->dimensions()}; } | |
| GrSurfaceOrigin origin() const { return fReadView.origin(); } | |
| skgpu::Swizzle readSwizzle() const { return fReadView.swizzle(); } | |
| // TODO: See if it makes sense for this to return a const& instead and require the callers to | |
| // make a copy (which refs the proxy) if needed. | |
| GrSurfaceProxyView readSurfaceView() { return fReadView; } | |
| SkISize dimensions() const { return fReadView.dimensions(); } | |
| int width() const { return fReadView.proxy()->width(); } | |
| int height() const { return fReadView.proxy()->height(); } | |
| skgpu::Mipmapped mipmapped() const { return fReadView.mipmapped(); } | |
| const GrCaps* caps() const; | |
| /** | |
| * Reads a rectangle of pixels from the surface context. | |
| * @param dContext The direct context to use | |
| * @param dst destination pixels for the read | |
| * @param srcPt offset w/in the surface context from which to read | |
| * is a GrDirectContext and fail otherwise. | |
| */ | |
| bool readPixels(GrDirectContext* dContext, GrPixmap dst, SkIPoint srcPt); | |
| using ReadPixelsCallback = SkImage::ReadPixelsCallback; | |
| using ReadPixelsContext = SkImage::ReadPixelsContext; | |
| using RescaleGamma = SkImage::RescaleGamma; | |
| using RescaleMode = SkImage::RescaleMode; | |
| // GPU implementation for SkImage:: and SkSurface::asyncRescaleAndReadPixels. | |
| void asyncRescaleAndReadPixels(GrDirectContext*, | |
| const SkImageInfo& info, | |
| const SkIRect& srcRect, | |
| RescaleGamma rescaleGamma, | |
| RescaleMode, | |
| ReadPixelsCallback callback, | |
| ReadPixelsContext callbackContext); | |
| // GPU implementation for SkImage:: and SkSurface::asyncRescaleAndReadPixelsYUV420. | |
| void asyncRescaleAndReadPixelsYUV420(GrDirectContext*, | |
| SkYUVColorSpace yuvColorSpace, | |
| bool readAlpha, | |
| sk_sp<SkColorSpace> dstColorSpace, | |
| const SkIRect& srcRect, | |
| SkISize dstSize, | |
| RescaleGamma rescaleGamma, | |
| RescaleMode, | |
| ReadPixelsCallback callback, | |
| ReadPixelsContext context); | |
| /** | |
| * Writes a rectangle of pixels from src into the surfaceDrawContext at the specified position. | |
| * @param dContext The direct context to use | |
| * @param src source for the write | |
| * @param dstPt offset w/in the surface context at which to write | |
| */ | |
| bool writePixels(GrDirectContext* dContext, | |
| GrCPixmap src, | |
| SkIPoint dstPt); | |
| /** | |
| * Fully populates either the base level or all MIP levels of the GrSurface with pixel data. | |
| * @param dContext The direct context to use | |
| * @param src Array of pixmaps | |
| * @param numLevels Number of pixmaps in src. To succeed this must be 1 or the total | |
| * number of MIP levels. | |
| */ | |
| bool writePixels(GrDirectContext* dContext, | |
| const GrCPixmap src[], | |
| int numLevels); | |
| GrSurfaceProxy* asSurfaceProxy() { return fReadView.proxy(); } | |
| const GrSurfaceProxy* asSurfaceProxy() const { return fReadView.proxy(); } | |
| sk_sp<GrSurfaceProxy> asSurfaceProxyRef() { return fReadView.refProxy(); } | |
| GrTextureProxy* asTextureProxy() { return fReadView.asTextureProxy(); } | |
| const GrTextureProxy* asTextureProxy() const { return fReadView.asTextureProxy(); } | |
| sk_sp<GrTextureProxy> asTextureProxyRef() { return fReadView.asTextureProxyRef(); } | |
| GrRenderTargetProxy* asRenderTargetProxy() { return fReadView.asRenderTargetProxy(); } | |
| const GrRenderTargetProxy* asRenderTargetProxy() const { | |
| return fReadView.asRenderTargetProxy(); | |
| } | |
| sk_sp<GrRenderTargetProxy> asRenderTargetProxyRef() { | |
| return fReadView.asRenderTargetProxyRef(); | |
| } | |
| virtual SurfaceFillContext* asFillContext() { return nullptr; } | |
| /** | |
| * Rescales the contents of srcRect. The gamma in which the rescaling occurs is controlled by | |
| * RescaleGamma. It is always in the original gamut. The result is converted to the color type | |
| * and color space of info after rescaling. Note: this currently requires that the info have a | |
| * different size than srcRect. Though, it could be relaxed to allow non-scaling color | |
| * conversions. | |
| */ | |
| std::unique_ptr<SurfaceFillContext> rescale(const GrImageInfo& info, | |
| GrSurfaceOrigin, | |
| SkIRect srcRect, | |
| SkImage::RescaleGamma, | |
| SkImage::RescaleMode); | |
| /** | |
| * Like the above but allows the caller ot specify a destination fill context and | |
| * rect within that context. The dst rect must be contained by the dst or this will fail. | |
| */ | |
| bool rescaleInto(SurfaceFillContext* dst, | |
| SkIRect dstRect, | |
| SkIRect srcRect, | |
| SkImage::RescaleGamma, | |
| SkImage::RescaleMode); | |
| #if defined(GPU_TEST_UTILS) | |
| bool testCopy(sk_sp<GrSurfaceProxy> src, const SkIRect& srcRect, const SkIPoint& dstPoint) { | |
| return this->copy(std::move(src), srcRect, dstPoint) != nullptr; | |
| } | |
| bool testCopy(sk_sp<GrSurfaceProxy> src) { | |
| auto rect = SkIRect::MakeSize(src->dimensions()); | |
| return this->copy(std::move(src), rect, {0, 0}) != nullptr; | |
| } | |
| #endif | |
| protected: | |
| GrDrawingManager* drawingManager(); | |
| const GrDrawingManager* drawingManager() const; | |
| SkDEBUGCODE(void validate() const;) | |
| SkDEBUGCODE(skgpu::SingleOwner* singleOwner() const;) | |
| GrRecordingContext* fContext; | |
| GrSurfaceProxyView fReadView; | |
| // Inserts a transfer, part of the implementation of asyncReadPixels and | |
| // asyncRescaleAndReadPixelsYUV420(). | |
| struct PixelTransferResult { | |
| using ConversionFn = void(void* dst, const void* mappedBuffer); | |
| // If null then the transfer could not be performed. Otherwise this buffer will contain | |
| // the pixel data when the transfer is complete. | |
| sk_sp<GrGpuBuffer> fTransferBuffer; | |
| // RowBytes for transfer buffer data | |
| size_t fRowBytes; | |
| // The task that is executed to perform the texture->buffer copy | |
| sk_sp<GrTransferFromRenderTask> fTransferTask; | |
| // If this is null then the transfer buffer will contain the data in the requested | |
| // color type. Otherwise, when the transfer is done this must be called to convert | |
| // from the transfer buffer's color type to the requested color type. | |
| std::function<ConversionFn> fPixelConverter; | |
| }; | |
| struct AsyncReadPixelContext; | |
| PixelTransferResult transferPixels(GrColorType colorType, const SkIRect& rect); | |
| // The async read step of asyncRescaleAndReadPixels() | |
| void asyncReadPixels(GrDirectContext*, | |
| const SkIRect& srcRect, | |
| SkColorType, | |
| ReadPixelsCallback, | |
| ReadPixelsContext); | |
| private: | |
| friend class ::GrRecordingContextPriv; // for validate | |
| friend class ::GrSurfaceProxy; // for copy | |
| SkDEBUGCODE(virtual void onValidate() const {}) | |
| /** | |
| * Copy 'src' into the proxy backing this context. This call will not do any draw fallback. | |
| * Currently only writePixels and replaceRenderTarget call this directly. All other copies | |
| * should go through GrSurfaceProxy::Copy. | |
| * @param src src of pixels | |
| * @param dstPoint the origin of the 'srcRect' in the destination coordinate space | |
| * @return a task (that may be skippable by calling canSkip) if successful and | |
| * null otherwise. | |
| * | |
| * Note: Notionally, 'srcRect' is clipped to 'src's extent with 'dstPoint' being adjusted. | |
| * Then the 'srcRect' offset by 'dstPoint' is clipped against the dst's extent. | |
| * The end result is only valid src pixels and dst pixels will be touched but the copied | |
| * regions will not be shifted. The 'src' must have the same origin as the backing proxy | |
| * of fSurfaceContext. | |
| */ | |
| sk_sp<GrRenderTask> copy(sk_sp<GrSurfaceProxy> src, SkIRect srcRect, SkIPoint dstPoint); | |
| /** | |
| * Copy and scale 'src' into the proxy backing this context. This call will not do any draw | |
| * fallback. Currently only rescaleInto() calls this directly, which handles drawing fallback | |
| * automatically. | |
| * | |
| * @param src src of pixels | |
| * @param srcRect the subset of src that is copied to this proxy | |
| * @param dstRect the subset of dst that receives the copied data, possibly with different | |
| * dimensions than 'srcRect'. | |
| * @param filterMode the filter mode to apply when scaling src | |
| * @return a task (that may be skippable by calling canSkip) if successful and | |
| * null otherwise. | |
| * | |
| * Note: Unlike copy(rect,point), 'srcRect' and 'dstRect' are not adjusted to fit within the | |
| * surfaces. If they are not contained, then nullptr is returned. The 'src' must have the same | |
| * origin as the backing proxy of this context. | |
| */ | |
| sk_sp<GrRenderTask> copyScaled(sk_sp<GrSurfaceProxy> src, SkIRect srcRect, SkIRect dstRect, | |
| GrSamplerState::Filter filterMode); | |
| bool internalWritePixels(GrDirectContext* dContext, | |
| const GrCPixmap src[], | |
| int numLevels, | |
| SkIPoint); | |
| GrColorInfo fColorInfo; | |
| using INHERITED = SkRefCnt; | |
| }; | |
| } // namespace skgpu::ganesh | |
| #endif // SurfaceContext_DEFINED |