Add drawDrawable support to GrRenderTargetContext.

This also includes adding drawable Op and plumbing it through to the GPU.

BUG=skia:

Change-Id: I0b2464c5a458c2fbf05b9528e47b9e6e3ac27d57
Reviewed-on: https://skia-review.googlesource.com/c/9645
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Greg Daniel 2018-10-19 13:54:56 -04:00 committed by Skia Commit-Bot
parent 6064e1c5d6
commit 64cc9aaaf1
14 changed files with 357 additions and 22 deletions

View File

@ -249,10 +249,13 @@ skia_gpu_sources = [
"$_src/gpu/ops/GrDashLinePathRenderer.h",
"$_src/gpu/ops/GrDashOp.cpp",
"$_src/gpu/ops/GrDashOp.h",
"$_src/gpu/ops/GrDebugMarkerOp.h",
"$_src/gpu/ops/GrDefaultPathRenderer.cpp",
"$_src/gpu/ops/GrDefaultPathRenderer.h",
"$_src/gpu/ops/GrDebugMarkerOp.cpp",
"$_src/gpu/ops/GrDebugMarkerOp.h",
"$_src/gpu/ops/GrDrawableOp.cpp",
"$_src/gpu/ops/GrDrawableOp.h",
"$_src/gpu/ops/GrDrawAtlasOp.cpp",
"$_src/gpu/ops/GrDrawAtlasOp.h",
"$_src/gpu/ops/GrDrawOp.h",

View File

@ -283,6 +283,7 @@ tests_sources = [
"$_tests/UtilsTest.cpp",
"$_tests/VerticesTest.cpp",
"$_tests/VkBackendSurfaceTest.cpp",
"$_tests/VkDrawableTest.cpp",
"$_tests/VkMakeCopyPipelineTest.cpp",
"$_tests/VkWrapTests.cpp",
"$_tests/VptrTest.cpp",

View File

@ -10,6 +10,7 @@
#include "GrColor.h"
#include "GrPipeline.h"
#include "SkDrawable.h"
#include "ops/GrDrawOp.h"
class GrOpFlushState;
@ -19,6 +20,7 @@ class GrMesh;
class GrPipeline;
class GrPrimitiveProcessor;
class GrRenderTarget;
class GrSemaphore;
struct SkIRect;
struct SkRect;
@ -117,6 +119,11 @@ public:
// TODO: This should be removed in the future to favor using the load and store ops for discard
virtual void discard() = 0;
/**
* Executes the SkDrawable object for the underlying backend.
*/
virtual void executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) {}
protected:
GrGpuRTCommandBuffer() : fOrigin(kTopLeft_GrSurfaceOrigin), fRenderTarget(nullptr) {}

View File

@ -26,6 +26,7 @@
#include "GrStencilAttachment.h"
#include "GrStyle.h"
#include "GrTracing.h"
#include "SkDrawable.h"
#include "SkDrawShadowInfo.h"
#include "SkGlyphRunPainter.h"
#include "SkGr.h"
@ -39,6 +40,7 @@
#include "ops/GrClearOp.h"
#include "ops/GrClearStencilClipOp.h"
#include "ops/GrDebugMarkerOp.h"
#include "ops/GrDrawableOp.h"
#include "ops/GrDrawAtlasOp.h"
#include "ops/GrDrawOp.h"
#include "ops/GrDrawVerticesOp.h"
@ -1442,6 +1444,13 @@ void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
this->addDrawOp(clip, std::move(op));
}
void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
const SkRect& bounds) {
std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
SkASSERT(op);
this->getRTOpList()->addOp(std::move(op), *this->caps());
}
GrSemaphoresSubmitted GrRenderTargetContext::prepareForExternalIO(
int numSemaphores, GrBackendSemaphore backendSemaphores[]) {
ASSERT_SINGLE_OWNER

View File

@ -17,6 +17,7 @@
#include "GrTypesPriv.h"
#include "GrXferProcessor.h"
#include "SkCanvas.h"
#include "SkDrawable.h"
#include "SkRefCnt.h"
#include "SkSurfaceProps.h"
#include "text/GrTextTarget.h"
@ -338,6 +339,12 @@ public:
std::unique_ptr<SkLatticeIter>,
const SkRect& dst);
/**
* Adds the necessary signal and wait semaphores and adds the passed in SkDrawable to the
* command stream.
*/
void drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>, const SkRect& bounds);
/**
* After this returns any pending surface IO will be issued to the backend 3D API and
* if the surface has MSAA it will be resolved.

View File

@ -1696,13 +1696,14 @@ void SkGpuDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkC
std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw =
drawable->snapGpuDrawHandler(api, combinedMatrix);
if (gpuDraw) {
// TODO: send the gpuDraw to the renderTargetContext and make an Op out of it
// return;
fRenderTargetContext->drawDrawable(std::move(gpuDraw), drawable->getBounds());
return;
}
}
this->INHERITED::drawDrawable(drawable, matrix, canvas);
}
///////////////////////////////////////////////////////////////////////////////
void SkGpuDevice::flush() {

View File

@ -0,0 +1,35 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrDrawableOp.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrGpuCommandBuffer.h"
#include "GrMemoryPool.h"
#include "GrOpFlushState.h"
#include "SkDrawable.h"
std::unique_ptr<GrDrawableOp> GrDrawableOp::Make(
GrContext* context, std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
const SkRect& bounds) {
GrOpMemoryPool* pool = context->contextPriv().opMemoryPool();
return pool->allocate<GrDrawableOp>(std::move(drawable), bounds);
}
GrDrawableOp::GrDrawableOp(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
const SkRect& bounds)
: INHERITED(ClassID())
, fDrawable(std::move(drawable)) {
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
}
void GrDrawableOp::onExecute(GrOpFlushState* state) {
SkASSERT(state->commandBuffer());
state->rtCommandBuffer()->executeDrawable(std::move(fDrawable));
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrDrawableOp_DEFINED
#define GrDrawableOp_DEFINED
#include "GrOp.h"
#include "GrSemaphore.h"
#include "SkDrawable.h"
#include "SkMatrix.h"
class GrDrawableOp final : public GrOp {
public:
DEFINE_OP_CLASS_ID
static std::unique_ptr<GrDrawableOp> Make(GrContext*,
std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
const SkRect& bounds);
const char* name() const override { return "Drawable"; }
SkString dumpInfo() const override {
return INHERITED::dumpInfo();
}
private:
friend class GrOpMemoryPool; // for ctor
GrDrawableOp(std::unique_ptr<SkDrawable::GpuDrawHandler>, const SkRect& bounds);
CombineResult onCombineIfPossible(GrOp* that, const GrCaps& caps) override {
return CombineResult::kCannotCombine;
}
void onPrepare(GrOpFlushState*) override {}
void onExecute(GrOpFlushState* state) override;
std::unique_ptr<SkDrawable::GpuDrawHandler> fDrawable;
typedef GrOp INHERITED;
};
#endif

View File

@ -311,6 +311,8 @@ public:
const GrVkRenderPass* compatibleRenderPass);
void end(const GrVkGpu* gpu);
VkCommandBuffer vkCommandBuffer() { return fCmdBuffer; }
#ifdef SK_TRACE_VK_RESOURCES
void dumpInfo() const override {
SkDebugf("GrVkSecondaryCommandBuffer: %d (%d refs)\n", fCmdBuffer, this->getRefCnt());

View File

@ -307,6 +307,9 @@ void GrVkGpu::submitCommandBuffer(SyncQueue sync) {
fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, fSemaphoresToSignal, fSemaphoresToWaitOn);
// We must delete and drawables that have been waitint till submit for us to destroy.
fDrawables.reset();
for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
fSemaphoresToWaitOn[i]->unref(this);
}
@ -2153,3 +2156,7 @@ sk_sp<GrSemaphore> GrVkGpu::prepareTextureForCrossContextUsage(GrTexture* textur
return nullptr;
}
void GrVkGpu::addDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
fDrawables.emplace_back(std::move(drawable));
}

View File

@ -141,6 +141,14 @@ public:
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
// These match the definitions in SkDrawable, from whence they came
typedef void* SubmitContext;
typedef void (*SubmitProc)(SubmitContext submitContext);
// Adds an SkDrawable::GpuDrawHandler that we will delete the next time we submit the primary
// command buffer to the gpu.
void addDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable);
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override;
void copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
@ -227,40 +235,42 @@ private:
size_t srcRowBytes, GrVkImageInfo* info);
#endif
sk_sp<const GrVkInterface> fInterface;
sk_sp<GrVkMemoryAllocator> fMemoryAllocator;
sk_sp<GrVkCaps> fVkCaps;
sk_sp<const GrVkInterface> fInterface;
sk_sp<GrVkMemoryAllocator> fMemoryAllocator;
sk_sp<GrVkCaps> fVkCaps;
VkInstance fInstance;
VkPhysicalDevice fPhysicalDevice;
VkDevice fDevice;
VkQueue fQueue; // Must be Graphics queue
uint32_t fQueueIndex;
VkInstance fInstance;
VkPhysicalDevice fPhysicalDevice;
VkDevice fDevice;
VkQueue fQueue; // Must be Graphics queue
uint32_t fQueueIndex;
// Created by GrVkGpu
GrVkResourceProvider fResourceProvider;
VkCommandPool fCmdPool;
GrVkResourceProvider fResourceProvider;
VkCommandPool fCmdPool;
GrVkPrimaryCommandBuffer* fCurrentCmdBuffer;
GrVkPrimaryCommandBuffer* fCurrentCmdBuffer;
SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToWaitOn;
SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToSignal;
SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToWaitOn;
SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToSignal;
VkPhysicalDeviceProperties fPhysDevProps;
VkPhysicalDeviceMemoryProperties fPhysDevMemProps;
SkTArray<std::unique_ptr<SkDrawable::GpuDrawHandler>> fDrawables;
GrVkCopyManager fCopyManager;
VkPhysicalDeviceProperties fPhysDevProps;
VkPhysicalDeviceMemoryProperties fPhysDevMemProps;
GrVkCopyManager fCopyManager;
// compiler used for compiling sksl into spirv. We only want to create the compiler once since
// there is significant overhead to the first compile of any compiler.
SkSL::Compiler* fCompiler;
SkSL::Compiler* fCompiler;
// We need a bool to track whether or not we've already disconnected all the gpu resources from
// vulkan context.
bool fDisconnected;
bool fDisconnected;
std::unique_ptr<GrVkGpuRTCommandBuffer> fCachedRTCommandBuffer;
std::unique_ptr<GrVkGpuTextureCommandBuffer> fCachedTexCommandBuffer;
std::unique_ptr<GrVkGpuRTCommandBuffer> fCachedRTCommandBuffer;
std::unique_ptr<GrVkGpuTextureCommandBuffer> fCachedTexCommandBuffer;
typedef GrGpu INHERITED;
};

View File

@ -7,6 +7,7 @@
#include "GrVkGpuCommandBuffer.h"
#include "GrBackendDrawableInfo.h"
#include "GrFixedClip.h"
#include "GrMesh.h"
#include "GrOpFlushState.h"
@ -19,7 +20,9 @@
#include "GrVkRenderPass.h"
#include "GrVkRenderTarget.h"
#include "GrVkResourceProvider.h"
#include "GrVkSemaphore.h"
#include "GrVkTexture.h"
#include "SkDrawable.h"
#include "SkRect.h"
void GrVkGpuTextureCommandBuffer::copy(GrSurface* src, GrSurfaceOrigin srcOrigin,
@ -267,6 +270,8 @@ void GrVkGpuRTCommandBuffer::reset() {
fRenderTarget = nullptr;
}
////////////////////////////////////////////////////////////////////////////////
void GrVkGpuRTCommandBuffer::discard() {
GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(fRenderTarget);
@ -777,3 +782,36 @@ void GrVkGpuRTCommandBuffer::sendIndexedInstancedMeshToGpu(GrPrimitiveType,
baseIndex, baseVertex, baseInstance);
fGpu->stats()->incNumDraws();
}
////////////////////////////////////////////////////////////////////////////////
void GrVkGpuRTCommandBuffer::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) {
GrVkRenderTarget* target = static_cast<GrVkRenderTarget*>(fRenderTarget);
GrVkImage* targetImage = target->msaaImage() ? target->msaaImage() : target;
CommandBufferInfo& cbInfo = fCommandBufferInfos[fCurrentCmdInfo];
VkRect2D bounds;
bounds.offset = { 0, 0 };
bounds.extent = { 0, 0 };
GrVkDrawableInfo vkInfo;
vkInfo.fSecondaryCommandBuffer = cbInfo.currentCmdBuf()->vkCommandBuffer();
vkInfo.fCompatibleRenderPass = cbInfo.fRenderPass->vkRenderPass();
SkAssertResult(cbInfo.fRenderPass->colorAttachmentIndex(&vkInfo.fImageAttachmentIndex));
vkInfo.fFormat = targetImage->imageFormat();
vkInfo.fDrawBounds = &bounds;
GrBackendDrawableInfo info(vkInfo);
drawable->draw(info);
fGpu->addDrawable(std::move(drawable));
if (bounds.extent.width == 0 || bounds.extent.height == 0) {
cbInfo.fBounds.join(target->getBoundsRect());
} else {
cbInfo.fBounds.join(SkRect::MakeXYWH(bounds.offset.x, bounds.offset.y,
bounds.extent.width, bounds.extent.height));
}
}

View File

@ -74,6 +74,8 @@ public:
void copy(GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
void executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) override;
void set(GrRenderTarget*, GrSurfaceOrigin,
const GrGpuRTCommandBuffer::LoadAndStoreInfo&,
const GrGpuRTCommandBuffer::StencilLoadAndStoreInfo&);

164
tests/VkDrawableTest.cpp Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// This is a GPU-backend specific test. It relies on static intializers to work
#include "SkTypes.h"
#if SK_SUPPORT_GPU && defined(SK_VULKAN)
#include "GrBackendDrawableInfo.h"
#include "GrContextFactory.h"
#include "GrContextPriv.h"
#include "SkDrawable.h"
#include "SkSurface.h"
#include "Test.h"
#include "vk/GrVkGpu.h"
#include "vk/GrVkInterface.h"
#include "vk/GrVkMemory.h"
#include "vk/GrVkUtil.h"
using sk_gpu_test::GrContextFactory;
static const int DEV_W = 16, DEV_H = 16;
class TestDrawable : public SkDrawable {
public:
TestDrawable(const GrVkInterface* interface, int32_t width, int32_t height)
: INHERITED()
, fInterface(interface)
, fWidth(width)
, fHeight(height) {}
~TestDrawable() override {}
class DrawHandler : public GpuDrawHandler {
public:
DrawHandler(const GrVkInterface* interface, int32_t width, int32_t height)
: INHERITED()
, fInterface(interface)
, fWidth(width)
, fHeight(height) {}
~DrawHandler() override {}
void draw(const GrBackendDrawableInfo& info) override {
GrVkDrawableInfo vkInfo;
SkAssertResult(info.getVkDrawableInfo(&vkInfo));
// Clear to Red
VkClearColorValue vkColor;
vkColor.float32[0] = 1.0f; // r
vkColor.float32[1] = 0.0f; // g
vkColor.float32[2] = 0.0f; // b
vkColor.float32[3] = 1.0f; // a
// Clear right half of render target
VkClearRect clearRect;
clearRect.rect.offset = { fWidth / 2, 0 };
clearRect.rect.extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
VkClearAttachment attachment;
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
attachment.colorAttachment = vkInfo.fImageAttachmentIndex;
attachment.clearValue.color = vkColor;
GR_VK_CALL(fInterface, CmdClearAttachments(vkInfo.fSecondaryCommandBuffer,
1,
&attachment,
1,
&clearRect));
vkInfo.fDrawBounds->offset = { fWidth / 2, 0 };
vkInfo.fDrawBounds->extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight };
}
private:
const GrVkInterface* fInterface;
int32_t fWidth;
int32_t fHeight;
typedef GpuDrawHandler INHERITED;
};
std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi,
const SkMatrix& matrix) override {
if (backendApi != GrBackendApi::kVulkan) {
return nullptr;
}
std::unique_ptr<DrawHandler> draw(new DrawHandler(fInterface, fWidth, fHeight));
return std::move(draw);
}
SkRect onGetBounds() override {
return SkRect::MakeLTRB(fWidth / 2, 0, fWidth, fHeight);
}
void onDraw(SkCanvas*) override {
SkASSERT(false);
}
private:
const GrVkInterface* fInterface;
int32_t fWidth;
int32_t fHeight;
typedef SkDrawable INHERITED;
};
void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context) {
GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
const SkImageInfo ii = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo,
ii, 0, kTopLeft_GrSurfaceOrigin, nullptr));
SkCanvas* canvas = surface->getCanvas();
canvas->clear(SK_ColorBLUE);
sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), DEV_W, DEV_H));
canvas->drawDrawable(drawable.get());
SkPaint paint;
paint.setColor(SK_ColorGREEN);
SkIRect rect = SkIRect::MakeLTRB(0, DEV_H/2, DEV_W, DEV_H);
canvas->drawIRect(rect, paint);
// read pixels
SkBitmap bitmap;
bitmap.allocPixels(ii);
canvas->readPixels(bitmap, 0, 0);
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) {
SkPMColor canvasPixel = canvasPixels[cy * DEV_W + cx];
if (cy < DEV_H / 2) {
if (cx < DEV_W / 2) {
expectedPixel = 0xFFFF0000; // Blue
} else {
expectedPixel = 0xFF0000FF; // Red
}
} else {
expectedPixel = 0xFF00FF00; // Green
}
if (expectedPixel != canvasPixel) {
failureFound = true;
ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
cx, cy, canvasPixel, expectedPixel);
}
}
}
}
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkDrawableTest, reporter, ctxInfo) {
draw_drawable_test(reporter, ctxInfo.grContext());
}
#endif