123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /*
- * 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 "include/core/SkTypes.h"
- #if SK_SUPPORT_GPU && defined(SK_VULKAN)
- #include "include/gpu/vk/GrVkVulkan.h"
- #include "include/core/SkDrawable.h"
- #include "include/core/SkSurface.h"
- #include "include/gpu/GrBackendDrawableInfo.h"
- #include "src/gpu/GrContextPriv.h"
- #include "src/gpu/vk/GrVkGpu.h"
- #include "src/gpu/vk/GrVkInterface.h"
- #include "src/gpu/vk/GrVkMemory.h"
- #include "src/gpu/vk/GrVkSecondaryCBDrawContext.h"
- #include "src/gpu/vk/GrVkUtil.h"
- #include "tests/Test.h"
- #include "tools/gpu/GrContextFactory.h"
- using sk_gpu_test::GrContextFactory;
- static const int DEV_W = 16, DEV_H = 16;
- class TestDrawable : public SkDrawable {
- public:
- TestDrawable(const GrVkInterface* interface, GrContext* context, int32_t width, int32_t height)
- : INHERITED()
- , fInterface(interface)
- , fContext(context)
- , fWidth(width)
- , fHeight(height) {}
- ~TestDrawable() override {}
- class DrawHandlerBasic : public GpuDrawHandler {
- public:
- DrawHandlerBasic(const GrVkInterface* interface, int32_t width, int32_t height)
- : INHERITED()
- , fInterface(interface)
- , fWidth(width)
- , fHeight(height) {}
- ~DrawHandlerBasic() 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.fColorAttachmentIndex;
- 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;
- };
- typedef void (*DrawProc)(TestDrawable*, const SkMatrix&, const SkIRect&,
- const SkImageInfo&, 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,
- const SkMatrix& matrix,
- const SkIRect& clipBounds,
- const SkImageInfo& bufferInfo)
- : INHERITED()
- , fTestDrawable(td)
- , fDrawProc(drawProc)
- , fSubmitProc(submitProc)
- , fMatrix(matrix)
- , fClipBounds(clipBounds)
- , fBufferInfo(bufferInfo) {}
- ~DrawHandlerImport() override {
- fSubmitProc(fTestDrawable);
- }
- void draw(const GrBackendDrawableInfo& info) override {
- GrVkDrawableInfo vkInfo;
- SkAssertResult(info.getVkDrawableInfo(&vkInfo));
- fDrawProc(fTestDrawable, fMatrix, fClipBounds, fBufferInfo, vkInfo);
- }
- private:
- TestDrawable* fTestDrawable;
- DrawProc fDrawProc;
- SubmitProc fSubmitProc;
- const SkMatrix fMatrix;
- const SkIRect fClipBounds;
- const SkImageInfo fBufferInfo;
- 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 SkMatrix& matrix, const SkIRect& clipBounds,
- const SkImageInfo& bufferInfo, const GrVkDrawableInfo& info) {
- td->fDrawContext = GrVkSecondaryCBDrawContext::Make(td->fContext, bufferInfo, info, nullptr);
- if (!td->fDrawContext) {
- return;
- }
- SkCanvas* canvas = td->fDrawContext->getCanvas();
- canvas->clipRect(SkRect::Make(clipBounds));
- canvas->setMatrix(matrix);
- 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,
- bufferInfo);
- 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->priv().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,
- const SkImageInfo& bufferInfo) override {
- if (backendApi != GrBackendApi::kVulkan) {
- return nullptr;
- }
- std::unique_ptr<GpuDrawHandler> draw;
- if (fContext) {
- draw.reset(new DrawHandlerImport(this, ImportDraw, ImportSubmitted, matrix,
- clipBounds, bufferInfo));
- } else {
- draw.reset(new DrawHandlerBasic(fInterface, fWidth, fHeight));
- }
- return draw;
- }
- SkRect onGetBounds() override {
- return SkRect::MakeLTRB(fWidth / 2, 0, fWidth, fHeight);
- }
- void onDraw(SkCanvas*) override {
- SkASSERT(false);
- }
- private:
- const GrVkInterface* fInterface;
- GrContext* fContext;
- sk_sp<GrVkSecondaryCBDrawContext> fDrawContext;
- int32_t fWidth;
- int32_t fHeight;
- typedef SkDrawable INHERITED;
- };
- void draw_drawable_test(skiatest::Reporter* reporter, GrContext* context, GrContext* childContext) {
- GrVkGpu* gpu = static_cast<GrVkGpu*>(context->priv().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(), childContext, 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(), 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);
- 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
|