blob: 1fc7c3e6ff5c9ead3ac58172d405a248db92fe4a [file] [log] [blame]
/*
* Copyright 2021 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/graphite/task/CopyTask.h"
#include "src/gpu/graphite/Buffer.h"
#include "src/gpu/graphite/CommandBuffer.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/Texture.h"
#include "src/gpu/graphite/TextureProxy.h"
namespace skgpu::graphite {
sk_sp<CopyBufferToBufferTask> CopyBufferToBufferTask::Make(const Buffer* srcBuffer,
size_t srcOffset,
sk_sp<Buffer> dstBuffer,
size_t dstOffset,
size_t size) {
SkASSERT(srcBuffer);
SkASSERT(size <= srcBuffer->size() - srcOffset);
SkASSERT(dstBuffer);
SkASSERT(size <= dstBuffer->size() - dstOffset);
return sk_sp<CopyBufferToBufferTask>(new CopyBufferToBufferTask(srcBuffer,
srcOffset,
std::move(dstBuffer),
dstOffset,
size));
}
CopyBufferToBufferTask::CopyBufferToBufferTask(const Buffer* srcBuffer,
size_t srcOffset,
sk_sp<Buffer> dstBuffer,
size_t dstOffset,
size_t size)
: fSrcBuffer(srcBuffer)
, fSrcOffset(srcOffset)
, fDstBuffer(std::move(dstBuffer))
, fDstOffset(dstOffset)
, fSize(size) {}
CopyBufferToBufferTask::~CopyBufferToBufferTask() = default;
Task::Status CopyBufferToBufferTask::prepareResources(ResourceProvider*,
ScratchResourceManager*,
const RuntimeEffectDictionary*) {
return Status::kSuccess;
}
Task::Status CopyBufferToBufferTask::addCommands(Context*,
CommandBuffer* commandBuffer,
ReplayTargetData) {
if (commandBuffer->copyBufferToBuffer(fSrcBuffer, fSrcOffset, fDstBuffer, fDstOffset, fSize)) {
return Status::kSuccess;
} else {
return Status::kFail;
}
}
sk_sp<CopyTextureToBufferTask> CopyTextureToBufferTask::Make(sk_sp<TextureProxy> textureProxy,
SkIRect srcRect,
sk_sp<Buffer> buffer,
size_t bufferOffset,
size_t bufferRowBytes) {
if (!textureProxy) {
return nullptr;
}
return sk_sp<CopyTextureToBufferTask>(new CopyTextureToBufferTask(std::move(textureProxy),
srcRect,
std::move(buffer),
bufferOffset,
bufferRowBytes));
}
CopyTextureToBufferTask::CopyTextureToBufferTask(sk_sp<TextureProxy> textureProxy,
SkIRect srcRect,
sk_sp<Buffer> buffer,
size_t bufferOffset,
size_t bufferRowBytes)
: fTextureProxy(std::move(textureProxy))
, fSrcRect(srcRect)
, fBuffer(std::move(buffer))
, fBufferOffset(bufferOffset)
, fBufferRowBytes(bufferRowBytes) {
}
CopyTextureToBufferTask::~CopyTextureToBufferTask() {}
Task::Status CopyTextureToBufferTask::prepareResources(ResourceProvider* resourceProvider,
ScratchResourceManager*,
const RuntimeEffectDictionary*) {
// If the source texture hasn't been instantiated yet, it means there was no prior task that
// could have initialized its contents so a readback to a buffer does not make sense.
SkASSERT(fTextureProxy->isInstantiated() || fTextureProxy->isLazy());
// TODO: The copy is also a consumer of the source, so it should participate in returning
// scratch resources like RenderPassTask does. For now, though, all copy tasks side step reuse
// entirely and they cannot participate until they've been moved into scoping tasks like
// DrawTask first.
return Status::kSuccess;
}
Task::Status CopyTextureToBufferTask::addCommands(Context*,
CommandBuffer* commandBuffer,
ReplayTargetData) {
if (commandBuffer->copyTextureToBuffer(fTextureProxy->refTexture(),
fSrcRect,
std::move(fBuffer),
fBufferOffset,
fBufferRowBytes)) {
// TODO(b/332681367): CopyTextureToBuffer is currently only used for readback operations,
// which are a one-time event. Should this just default to returning kDiscard?
return Status::kSuccess;
} else {
return Status::kFail;
}
}
//--------------------------------------------------------------------------------------------------
sk_sp<CopyTextureToTextureTask> CopyTextureToTextureTask::Make(sk_sp<TextureProxy> srcProxy,
SkIRect srcRect,
sk_sp<TextureProxy> dstProxy,
SkIPoint dstPoint,
int dstLevel) {
if (!srcProxy || !dstProxy) {
return nullptr;
}
return sk_sp<CopyTextureToTextureTask>(new CopyTextureToTextureTask(std::move(srcProxy),
srcRect,
std::move(dstProxy),
dstPoint,
dstLevel));
}
CopyTextureToTextureTask::CopyTextureToTextureTask(sk_sp<TextureProxy> srcProxy,
SkIRect srcRect,
sk_sp<TextureProxy> dstProxy,
SkIPoint dstPoint,
int dstLevel)
: fSrcProxy(std::move(srcProxy))
, fSrcRect(srcRect)
, fDstProxy(std::move(dstProxy))
, fDstPoint(dstPoint)
, fDstLevel(dstLevel) {}
CopyTextureToTextureTask::~CopyTextureToTextureTask() {}
Task::Status CopyTextureToTextureTask::prepareResources(ResourceProvider* resourceProvider,
ScratchResourceManager*,
const RuntimeEffectDictionary*) {
// Do not instantiate the src proxy. If the source texture hasn't been instantiated yet, it
// means there was no prior task that could have initialized its contents so propagating the
// undefined contents to the dst does not make sense.
// TODO(b/333729316): Assert that fSrcProxy is instantiated or lazy; right now it may not be
// instantatiated if this is a dst readback copy for a scratch Device. In that case, a
// RenderPassTask will immediately follow this copy task and instantiate the source proxy so
// that addCommands() has a texture to operate on. That said, the texture's contents will be
// undefined when the copy is executed ideally it just shouldn't happen.
// TODO: The copy is also a consumer of the source, so it should participate in returning
// scratch resources like RenderPassTask does. For now, though, all copy tasks side step reuse
// entirely and they cannot participate until they've been moved into scoping tasks like
// DrawTask first. In particular, for texture-to-texture copies, they should be scoped to not
// invoke pending listeners for a subsequent RenderPassTask.
// TODO: Use the scratch resource manager to instantiate fDstProxy, although the details of when
// that texture can be returned need to be worked out. While brittle, all current use cases
// of scratch texture-to-texture copies have the dst used immediately by the next task, so it
// could just add a pending listener that returns the texture w/o any read counting.
if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fDstProxy.get())) {
SKGPU_LOG_E("Could not instantiate dst texture proxy for CopyTextureToTextureTask!");
return Status::kFail;
}
return Status::kSuccess;
}
Task::Status CopyTextureToTextureTask::addCommands(Context*,
CommandBuffer* commandBuffer,
ReplayTargetData) {
// prepareResources() doesn't instantiate the source assuming that a prior task will have do so
// as part of initializing the texture contents.
SkASSERT(fSrcProxy->isInstantiated());
if (commandBuffer->copyTextureToTexture(fSrcProxy->refTexture(),
fSrcRect,
fDstProxy->refTexture(),
fDstPoint,
fDstLevel)) {
// TODO(b/332681367): The calling context should be able to specify whether or not this copy
// is a repeatable operation (e.g. dst readback copy for blending) or one time (e.g. client
// asked for a copy of an image or surface).
return Status::kSuccess;
} else {
return Status::kFail;
}
}
} // namespace skgpu::graphite