Add support to gpu command buffers to wrap an external command buffer.
Bug: skia: Change-Id: Ic679d292f42c61f9f1c36315ae605504a0283306 Reviewed-on: https://skia-review.googlesource.com/c/179521 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
0ae5f90985
commit
070cbafd6b
@ -523,9 +523,15 @@ void GrRenderTargetOpList::fullClear(GrContext* context, const SkPMColor4f& colo
|
||||
if (this->isEmpty() || !fTarget.get()->asRenderTargetProxy()->needsStencil()) {
|
||||
this->deleteOps();
|
||||
fDeferredProxies.reset();
|
||||
fColorLoadOp = GrLoadOp::kClear;
|
||||
fLoadClearColor = color;
|
||||
return;
|
||||
|
||||
// If the opList is using a render target which wraps a vulkan command buffer, we can't do a
|
||||
// clear load since we cannot change the render pass that we are using. Thus we fall back to
|
||||
// making a clear op in this case.
|
||||
if (!fTarget.get()->asRenderTargetProxy()->wrapsVkSecondaryCB()) {
|
||||
fColorLoadOp = GrLoadOp::kClear;
|
||||
fLoadClearColor = color;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GrClearOp> op(GrClearOp::Make(context, GrFixedClip::Disabled(),
|
||||
|
@ -58,8 +58,10 @@ void GrVkCommandBuffer::freeGPUData(GrVkGpu* gpu) const {
|
||||
fTrackedRecordingResources[i]->unref(gpu);
|
||||
}
|
||||
|
||||
GR_VK_CALL(gpu->vkInterface(), FreeCommandBuffers(gpu->device(), fCmdPool->vkCommandPool(), 1,
|
||||
&fCmdBuffer));
|
||||
if (!this->isWrapped()) {
|
||||
GR_VK_CALL(gpu->vkInterface(), FreeCommandBuffers(gpu->device(), fCmdPool->vkCommandPool(),
|
||||
1, &fCmdBuffer));
|
||||
}
|
||||
|
||||
this->onFreeGPUData(gpu);
|
||||
}
|
||||
@ -131,6 +133,7 @@ void GrVkCommandBuffer::pipelineBarrier(const GrVkGpu* gpu,
|
||||
bool byRegion,
|
||||
BarrierType barrierType,
|
||||
void* barrier) const {
|
||||
SkASSERT(!this->isWrapped());
|
||||
SkASSERT(fIsActive);
|
||||
// For images we can have barriers inside of render passes but they require us to add more
|
||||
// support in subpasses which need self dependencies to have barriers inside them. Also, we can
|
||||
@ -835,6 +838,7 @@ void GrVkPrimaryCommandBuffer::onAbandonGPUData() const {
|
||||
|
||||
GrVkSecondaryCommandBuffer* GrVkSecondaryCommandBuffer::Create(const GrVkGpu* gpu,
|
||||
GrVkCommandPool* cmdPool) {
|
||||
SkASSERT(cmdPool);
|
||||
const VkCommandBufferAllocateInfo cmdInfo = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // sType
|
||||
nullptr, // pNext
|
||||
@ -853,6 +857,9 @@ GrVkSecondaryCommandBuffer* GrVkSecondaryCommandBuffer::Create(const GrVkGpu* gp
|
||||
return new GrVkSecondaryCommandBuffer(cmdBuffer, cmdPool);
|
||||
}
|
||||
|
||||
GrVkSecondaryCommandBuffer* GrVkSecondaryCommandBuffer::Create(VkCommandBuffer cmdBuffer) {
|
||||
return new GrVkSecondaryCommandBuffer(cmdBuffer, nullptr);
|
||||
}
|
||||
|
||||
void GrVkSecondaryCommandBuffer::begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer,
|
||||
const GrVkRenderPass* compatibleRenderPass) {
|
||||
@ -860,33 +867,37 @@ void GrVkSecondaryCommandBuffer::begin(const GrVkGpu* gpu, const GrVkFramebuffer
|
||||
SkASSERT(compatibleRenderPass);
|
||||
fActiveRenderPass = compatibleRenderPass;
|
||||
|
||||
VkCommandBufferInheritanceInfo inheritanceInfo;
|
||||
memset(&inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
|
||||
inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
|
||||
inheritanceInfo.pNext = nullptr;
|
||||
inheritanceInfo.renderPass = fActiveRenderPass->vkRenderPass();
|
||||
inheritanceInfo.subpass = 0; // Currently only using 1 subpass for each render pass
|
||||
inheritanceInfo.framebuffer = framebuffer ? framebuffer->framebuffer() : VK_NULL_HANDLE;
|
||||
inheritanceInfo.occlusionQueryEnable = false;
|
||||
inheritanceInfo.queryFlags = 0;
|
||||
inheritanceInfo.pipelineStatistics = 0;
|
||||
if (!this->isWrapped()) {
|
||||
VkCommandBufferInheritanceInfo inheritanceInfo;
|
||||
memset(&inheritanceInfo, 0, sizeof(VkCommandBufferInheritanceInfo));
|
||||
inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
|
||||
inheritanceInfo.pNext = nullptr;
|
||||
inheritanceInfo.renderPass = fActiveRenderPass->vkRenderPass();
|
||||
inheritanceInfo.subpass = 0; // Currently only using 1 subpass for each render pass
|
||||
inheritanceInfo.framebuffer = framebuffer ? framebuffer->framebuffer() : VK_NULL_HANDLE;
|
||||
inheritanceInfo.occlusionQueryEnable = false;
|
||||
inheritanceInfo.queryFlags = 0;
|
||||
inheritanceInfo.pipelineStatistics = 0;
|
||||
|
||||
VkCommandBufferBeginInfo cmdBufferBeginInfo;
|
||||
memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
|
||||
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
cmdBufferBeginInfo.pNext = nullptr;
|
||||
cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
|
||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
cmdBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
|
||||
VkCommandBufferBeginInfo cmdBufferBeginInfo;
|
||||
memset(&cmdBufferBeginInfo, 0, sizeof(VkCommandBufferBeginInfo));
|
||||
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
cmdBufferBeginInfo.pNext = nullptr;
|
||||
cmdBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT |
|
||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
cmdBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
|
||||
|
||||
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
|
||||
&cmdBufferBeginInfo));
|
||||
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), BeginCommandBuffer(fCmdBuffer,
|
||||
&cmdBufferBeginInfo));
|
||||
}
|
||||
fIsActive = true;
|
||||
}
|
||||
|
||||
void GrVkSecondaryCommandBuffer::end(GrVkGpu* gpu) {
|
||||
SkASSERT(fIsActive);
|
||||
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
|
||||
if (!this->isWrapped()) {
|
||||
GR_VK_CALL_ERRCHECK(gpu->vkInterface(), EndCommandBuffer(fCmdBuffer));
|
||||
}
|
||||
this->invalidateState();
|
||||
fIsActive = false;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public:
|
||||
|
||||
protected:
|
||||
GrVkCommandBuffer(VkCommandBuffer cmdBuffer, GrVkCommandPool* cmdPool,
|
||||
const GrVkRenderPass* rp = VK_NULL_HANDLE)
|
||||
const GrVkRenderPass* rp = nullptr)
|
||||
: fIsActive(false)
|
||||
, fActiveRenderPass(rp)
|
||||
, fCmdBuffer(cmdBuffer)
|
||||
@ -144,6 +144,10 @@ protected:
|
||||
this->invalidateState();
|
||||
}
|
||||
|
||||
bool isWrapped() const {
|
||||
return fCmdPool == nullptr;
|
||||
}
|
||||
|
||||
SkTDArray<const GrVkResource*> fTrackedResources;
|
||||
SkTDArray<const GrVkRecycledResource*> fTrackedRecycledResources;
|
||||
SkTDArray<const GrVkResource*> fTrackedRecordingResources;
|
||||
@ -326,6 +330,8 @@ private:
|
||||
class GrVkSecondaryCommandBuffer : public GrVkCommandBuffer {
|
||||
public:
|
||||
static GrVkSecondaryCommandBuffer* Create(const GrVkGpu* gpu, GrVkCommandPool* cmdPool);
|
||||
// Used for wrapping an external secondary command buffer.
|
||||
static GrVkSecondaryCommandBuffer* Create(VkCommandBuffer externalSecondaryCB);
|
||||
|
||||
void begin(const GrVkGpu* gpu, const GrVkFramebuffer* framebuffer,
|
||||
const GrVkRenderPass* compatibleRenderPass);
|
||||
|
@ -127,6 +127,21 @@ void GrVkGpuRTCommandBuffer::init() {
|
||||
cbInfo.currentCmdBuf()->begin(fGpu, vkRT->framebuffer(), cbInfo.fRenderPass);
|
||||
}
|
||||
|
||||
void GrVkGpuRTCommandBuffer::initWrapped() {
|
||||
CommandBufferInfo& cbInfo = fCommandBufferInfos.push_back();
|
||||
SkASSERT(fCommandBufferInfos.count() == 1);
|
||||
fCurrentCmdInfo = 0;
|
||||
|
||||
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
|
||||
SkASSERT(vkRT->wrapsSecondaryCommandBuffer());
|
||||
cbInfo.fRenderPass = vkRT->externalRenderPass();
|
||||
cbInfo.fRenderPass->ref();
|
||||
|
||||
cbInfo.fBounds.setEmpty();
|
||||
cbInfo.fCommandBuffers.push_back(vkRT->getExternalSecondaryCommandBuffer());
|
||||
cbInfo.fCommandBuffers[0]->ref();
|
||||
cbInfo.currentCmdBuf()->begin(fGpu, nullptr, cbInfo.fRenderPass);
|
||||
}
|
||||
|
||||
GrVkGpuRTCommandBuffer::~GrVkGpuRTCommandBuffer() {
|
||||
this->reset();
|
||||
@ -176,6 +191,23 @@ void GrVkGpuRTCommandBuffer::submit() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't want to actually submit the secondary command buffer if it is wrapped.
|
||||
if (this->wrapsSecondaryCommandBuffer()) {
|
||||
// If we have any sampled images set their layout now.
|
||||
for (int j = 0; j < cbInfo.fSampledImages.count(); ++j) {
|
||||
cbInfo.fSampledImages[j]->setImageLayout(fGpu,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_ACCESS_SHADER_READ_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
false);
|
||||
}
|
||||
|
||||
// There should have only been one secondary command buffer in the wrapped case so it is
|
||||
// safe to just return here.
|
||||
SkASSERT(fCommandBufferInfos.count() == 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure if we only have a discard load that we execute the discard on the whole image.
|
||||
// TODO: Once we improve our tracking of discards so that we never end up flushing a discard
|
||||
// call with no actually ops, remove this.
|
||||
@ -244,6 +276,11 @@ void GrVkGpuRTCommandBuffer::set(GrRenderTarget* rt, GrSurfaceOrigin origin,
|
||||
|
||||
this->INHERITED::set(rt, origin);
|
||||
|
||||
if (this->wrapsSecondaryCommandBuffer()) {
|
||||
this->initWrapped();
|
||||
return;
|
||||
}
|
||||
|
||||
fClearColor = colorInfo.fClearColor;
|
||||
|
||||
get_vk_load_store_ops(colorInfo.fLoadOp, colorInfo.fStoreOp,
|
||||
@ -271,6 +308,11 @@ void GrVkGpuRTCommandBuffer::reset() {
|
||||
fRenderTarget = nullptr;
|
||||
}
|
||||
|
||||
bool GrVkGpuRTCommandBuffer::wrapsSecondaryCommandBuffer() const {
|
||||
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
|
||||
return vkRT->wrapsSecondaryCommandBuffer();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GrVkGpuRTCommandBuffer::discard() {
|
||||
|
@ -87,6 +87,12 @@ public:
|
||||
private:
|
||||
void init();
|
||||
|
||||
// Called instead of init when we are drawing to a render target that already wraps a secondary
|
||||
// command buffer.
|
||||
void initWrapped();
|
||||
|
||||
bool wrapsSecondaryCommandBuffer() const;
|
||||
|
||||
GrGpu* gpu() override;
|
||||
|
||||
// Bind vertex and index buffers
|
||||
|
@ -115,7 +115,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
|
||||
const GrVkImageInfo& info,
|
||||
sk_sp<GrVkImageLayout> layout,
|
||||
const GrVkRenderPass* renderPass,
|
||||
VkCommandBuffer secondaryCommandBuffer)
|
||||
GrVkSecondaryCommandBuffer* secondaryCommandBuffer)
|
||||
: GrSurface(gpu, desc)
|
||||
, GrVkImage(info, std::move(layout), GrBackendObjectOwnership::kBorrowed, true)
|
||||
, GrRenderTarget(gpu, desc)
|
||||
@ -219,8 +219,13 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, desc, info, std::move(layout), rp,
|
||||
vkInfo.fSecondaryCommandBuffer);
|
||||
GrVkSecondaryCommandBuffer* scb =
|
||||
GrVkSecondaryCommandBuffer::Create(vkInfo.fSecondaryCommandBuffer);
|
||||
if (!scb) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, desc, info, std::move(layout), rp, scb);
|
||||
|
||||
return sk_sp<GrVkRenderTarget>(vkRT);
|
||||
}
|
||||
@ -284,6 +289,7 @@ GrVkRenderTarget::~GrVkRenderTarget() {
|
||||
SkASSERT(!fColorAttachmentView);
|
||||
SkASSERT(!fFramebuffer);
|
||||
SkASSERT(!fCachedSimpleRenderPass);
|
||||
SkASSERT(!fSecondaryCommandBuffer);
|
||||
}
|
||||
|
||||
void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const {
|
||||
@ -321,6 +327,10 @@ void GrVkRenderTarget::releaseInternalObjects() {
|
||||
fCachedSimpleRenderPass->unref(gpu);
|
||||
fCachedSimpleRenderPass = nullptr;
|
||||
}
|
||||
if (fSecondaryCommandBuffer) {
|
||||
fSecondaryCommandBuffer->unref(gpu);
|
||||
fSecondaryCommandBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GrVkRenderTarget::abandonInternalObjects() {
|
||||
@ -345,6 +355,10 @@ void GrVkRenderTarget::abandonInternalObjects() {
|
||||
fCachedSimpleRenderPass->unrefAndAbandon();
|
||||
fCachedSimpleRenderPass = nullptr;
|
||||
}
|
||||
if (fSecondaryCommandBuffer) {
|
||||
fSecondaryCommandBuffer->unrefAndAbandon();
|
||||
fSecondaryCommandBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GrVkRenderTarget::onRelease() {
|
||||
|
@ -20,6 +20,7 @@ class GrVkCommandBuffer;
|
||||
class GrVkFramebuffer;
|
||||
class GrVkGpu;
|
||||
class GrVkImageView;
|
||||
class GrVkSecondaryCommandBuffer;
|
||||
class GrVkStencilAttachment;
|
||||
|
||||
struct GrVkImageInfo;
|
||||
@ -67,7 +68,10 @@ public:
|
||||
return fCachedSimpleRenderPass;
|
||||
}
|
||||
|
||||
bool wrapsSecondaryCommandBuffer() const { return fSecondaryCommandBuffer != VK_NULL_HANDLE; }
|
||||
bool wrapsSecondaryCommandBuffer() const { return fSecondaryCommandBuffer != nullptr; }
|
||||
GrVkSecondaryCommandBuffer* getExternalSecondaryCommandBuffer() const {
|
||||
return fSecondaryCommandBuffer;
|
||||
}
|
||||
|
||||
// override of GrRenderTarget
|
||||
ResolveType getResolveType() const override {
|
||||
@ -152,7 +156,7 @@ private:
|
||||
const GrVkImageInfo& info,
|
||||
sk_sp<GrVkImageLayout> layout,
|
||||
const GrVkRenderPass* renderPass,
|
||||
VkCommandBuffer secondaryCommandBuffer);
|
||||
GrVkSecondaryCommandBuffer* secondaryCommandBuffer);
|
||||
|
||||
bool completeStencilAttachment() override;
|
||||
|
||||
@ -167,10 +171,11 @@ private:
|
||||
// This is a handle to be used to quickly get compatible GrVkRenderPasses for this render target
|
||||
GrVkResourceProvider::CompatibleRPHandle fCompatibleRPHandle;
|
||||
|
||||
// Handle to an external secondary command buffer which this GrVkRenderTarget represents. If
|
||||
// this is not VK_NULL_HANDLE then the GrVkRenderTarget does not have a real VkImage backing it,
|
||||
// and is limited in what it can be used for.
|
||||
VkCommandBuffer fSecondaryCommandBuffer = VK_NULL_HANDLE;
|
||||
// If this render target wraps an external VkCommandBuffer, then this pointer will be non-null
|
||||
// and will point to the GrVk object that, in turn, wraps the external VkCommandBuffer. In this
|
||||
// case the render target will not be backed by an actual VkImage and will thus be limited in
|
||||
// terms of what it can be used for.
|
||||
GrVkSecondaryCommandBuffer* fSecondaryCommandBuffer = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "vk/GrVkGpu.h"
|
||||
#include "vk/GrVkInterface.h"
|
||||
#include "vk/GrVkMemory.h"
|
||||
#include "vk/GrVkSecondaryCBDrawContext.h"
|
||||
#include "vk/GrVkUtil.h"
|
||||
|
||||
using sk_gpu_test::GrContextFactory;
|
||||
@ -30,22 +31,23 @@ static const int DEV_W = 16, DEV_H = 16;
|
||||
|
||||
class TestDrawable : public SkDrawable {
|
||||
public:
|
||||
TestDrawable(const GrVkInterface* interface, int32_t width, int32_t height)
|
||||
TestDrawable(const GrVkInterface* interface, GrContext* context, int32_t width, int32_t height)
|
||||
: INHERITED()
|
||||
, fInterface(interface)
|
||||
, fContext(context)
|
||||
, fWidth(width)
|
||||
, fHeight(height) {}
|
||||
|
||||
~TestDrawable() override {}
|
||||
|
||||
class DrawHandler : public GpuDrawHandler {
|
||||
class DrawHandlerBasic : public GpuDrawHandler {
|
||||
public:
|
||||
DrawHandler(const GrVkInterface* interface, int32_t width, int32_t height)
|
||||
DrawHandlerBasic(const GrVkInterface* interface, int32_t width, int32_t height)
|
||||
: INHERITED()
|
||||
, fInterface(interface)
|
||||
, fWidth(width)
|
||||
, fHeight(height) {}
|
||||
~DrawHandler() override {}
|
||||
~DrawHandlerBasic() override {}
|
||||
|
||||
void draw(const GrBackendDrawableInfo& info) override {
|
||||
GrVkDrawableInfo vkInfo;
|
||||
@ -86,14 +88,100 @@ public:
|
||||
typedef GpuDrawHandler INHERITED;
|
||||
};
|
||||
|
||||
typedef void (*DrawProc)(TestDrawable*, const GrVkDrawableInfo&);
|
||||
typedef void (*SubmitProc)(TestDrawable*);
|
||||
|
||||
// Exercises the exporting of a secondary command buffer from one GrContext and then importing
|
||||
// it into a second GrContext. We then draw to the secondary command buffer from the second
|
||||
// GrContext.
|
||||
class DrawHandlerImport : public GpuDrawHandler {
|
||||
public:
|
||||
DrawHandlerImport(TestDrawable* td, DrawProc drawProc, SubmitProc submitProc)
|
||||
: INHERITED()
|
||||
, fTestDrawable(td)
|
||||
, fDrawProc(drawProc)
|
||||
, fSubmitProc(submitProc) {}
|
||||
~DrawHandlerImport() override {
|
||||
fSubmitProc(fTestDrawable);
|
||||
}
|
||||
|
||||
void draw(const GrBackendDrawableInfo& info) override {
|
||||
GrVkDrawableInfo vkInfo;
|
||||
SkAssertResult(info.getVkDrawableInfo(&vkInfo));
|
||||
|
||||
fDrawProc(fTestDrawable, vkInfo);
|
||||
}
|
||||
private:
|
||||
TestDrawable* fTestDrawable;
|
||||
DrawProc fDrawProc;
|
||||
SubmitProc fSubmitProc;
|
||||
|
||||
typedef GpuDrawHandler INHERITED;
|
||||
};
|
||||
|
||||
// Helper function to test drawing to a secondary command buffer that we imported into the
|
||||
// GrContext using a GrVkSecondaryCBDrawContext.
|
||||
static void ImportDraw(TestDrawable* td, const GrVkDrawableInfo& info) {
|
||||
SkImageInfo imageInfo = SkImageInfo::Make(td->fWidth, td->fHeight, kRGBA_8888_SkColorType,
|
||||
kPremul_SkAlphaType);
|
||||
|
||||
td->fDrawContext = GrVkSecondaryCBDrawContext::Make(td->fContext, imageInfo, info, nullptr);
|
||||
if (!td->fDrawContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkCanvas* canvas = td->fDrawContext->getCanvas();
|
||||
SkIRect rect = SkIRect::MakeXYWH(td->fWidth/2, 0, td->fWidth/4, td->fHeight);
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorRED);
|
||||
canvas->drawIRect(rect, paint);
|
||||
|
||||
// Draw to an offscreen target so that we end up with a mix of "real" secondary command
|
||||
// buffers and the imported secondary command buffer.
|
||||
sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(td->fContext, SkBudgeted::kYes,
|
||||
imageInfo);
|
||||
surf->getCanvas()->clear(SK_ColorRED);
|
||||
|
||||
SkRect dstRect = SkRect::MakeXYWH(3*td->fWidth/4, 0, td->fWidth/4, td->fHeight);
|
||||
SkIRect srcRect = SkIRect::MakeWH(td->fWidth/4, td->fHeight);
|
||||
canvas->drawImageRect(surf->makeImageSnapshot(), srcRect, dstRect, &paint);
|
||||
|
||||
td->fDrawContext->flush();
|
||||
}
|
||||
|
||||
// Helper function to test waiting for the imported secondary command buffer to be submitted on
|
||||
// its original context and then cleaning up the GrVkSecondaryCBDrawContext from this GrContext.
|
||||
static void ImportSubmitted(TestDrawable* td) {
|
||||
// Typical use case here would be to create a fence that we submit to the gpu and then wait
|
||||
// on before releasing the GrVkSecondaryCBDrawContext resources. To simulate that for this
|
||||
// test (and since we are running single threaded anyways), we will just force a sync of
|
||||
// the gpu and cpu here.
|
||||
td->fContext->contextPriv().getGpu()->testingOnly_flushGpuAndSync();
|
||||
|
||||
td->fDrawContext->releaseResources();
|
||||
// We release the GrContext here manually to test that we waited long enough before
|
||||
// releasing the GrVkSecondaryCBDrawContext. This simulates when a client is able to delete
|
||||
// the GrContext it used to imported the secondary command buffer. If we had released the
|
||||
// GrContext's resources earlier (before waiting on the gpu above), we would get vulkan
|
||||
// validation layer errors saying we freed some vulkan objects while they were still in use
|
||||
// on the GPU.
|
||||
td->fContext->releaseResourcesAndAbandonContext();
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi,
|
||||
const SkMatrix& matrix,
|
||||
const SkIRect& clipBounds) override {
|
||||
if (backendApi != GrBackendApi::kVulkan) {
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<DrawHandler> draw(new DrawHandler(fInterface, fWidth, fHeight));
|
||||
return std::move(draw);
|
||||
std::unique_ptr<GpuDrawHandler> draw;
|
||||
if (fContext) {
|
||||
draw.reset(new DrawHandlerImport(this, ImportDraw, ImportSubmitted));
|
||||
} else {
|
||||
draw.reset(new DrawHandlerBasic(fInterface, fWidth, fHeight));
|
||||
}
|
||||
return draw;
|
||||
}
|
||||
|
||||
SkRect onGetBounds() override {
|
||||
@ -106,13 +194,15 @@ public:
|
||||
|
||||
private:
|
||||
const GrVkInterface* fInterface;
|
||||
int32_t fWidth;
|
||||
int32_t fHeight;
|
||||
GrContext* fContext;
|
||||
sk_sp<GrVkSecondaryCBDrawContext> fDrawContext;
|
||||
int32_t fWidth;
|
||||
int32_t fHeight;
|
||||
|
||||
typedef SkDrawable INHERITED;
|
||||
};
|
||||
|
||||
void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context) {
|
||||
void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context, GrContext* childContext) {
|
||||
GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
|
||||
|
||||
const SkImageInfo ii = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
|
||||
@ -122,7 +212,7 @@ void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context) {
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
canvas->clear(SK_ColorBLUE);
|
||||
|
||||
sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), DEV_W, DEV_H));
|
||||
sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), childContext, DEV_W, DEV_H));
|
||||
canvas->drawDrawable(drawable.get());
|
||||
|
||||
SkPaint paint;
|
||||
@ -138,8 +228,8 @@ void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context) {
|
||||
const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
|
||||
bool failureFound = false;
|
||||
SkPMColor expectedPixel;
|
||||
for (int cy = 0; cy < DEV_H || failureFound; ++cy) {
|
||||
for (int cx = 0; cx < DEV_W || failureFound; ++cx) {
|
||||
for (int cy = 0; cy < DEV_H && !failureFound; ++cy) {
|
||||
for (int cx = 0; cx < DEV_W && !failureFound; ++cx) {
|
||||
SkPMColor canvasPixel = canvasPixels[cy * DEV_W + cx];
|
||||
if (cy < DEV_H / 2) {
|
||||
if (cx < DEV_W / 2) {
|
||||
@ -159,9 +249,32 @@ void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkDrawableTest, reporter, ctxInfo) {
|
||||
draw_drawable_test(reporter, ctxInfo.grContext());
|
||||
draw_drawable_test(reporter, ctxInfo.grContext(), nullptr);
|
||||
}
|
||||
|
||||
DEF_GPUTEST(VkDrawableImportTest, reporter, options) {
|
||||
for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
|
||||
sk_gpu_test::GrContextFactory::ContextType contextType =
|
||||
(sk_gpu_test::GrContextFactory::ContextType) typeInt;
|
||||
if (contextType != sk_gpu_test::GrContextFactory::kVulkan_ContextType) {
|
||||
continue;
|
||||
}
|
||||
sk_gpu_test::GrContextFactory factory(options);
|
||||
sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(
|
||||
contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
|
||||
skiatest::ReporterContext ctx(
|
||||
reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
|
||||
if (ctxInfo.grContext()) {
|
||||
sk_gpu_test::ContextInfo child =
|
||||
factory.getSharedContextInfo(ctxInfo.grContext(), 0);
|
||||
if (!child.grContext()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
draw_drawable_test(reporter, ctxInfo.grContext(), child.grContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user