1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci// This is a GPU-backend specific test. It relies on static intializers to work 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 11cb93a386Sopenharmony_ci 12cb93a386Sopenharmony_ci#if SK_SUPPORT_GPU && defined(SK_VULKAN) 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci#include "include/gpu/vk/GrVkVulkan.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 17cb93a386Sopenharmony_ci#include "include/core/SkDrawable.h" 18cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 19cb93a386Sopenharmony_ci#include "include/gpu/GrBackendDrawableInfo.h" 20cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 22cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkGpu.h" 23cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkInterface.h" 24cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkMemory.h" 25cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkSecondaryCBDrawContext.h" 26cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkUtil.h" 27cb93a386Sopenharmony_ci#include "tests/Test.h" 28cb93a386Sopenharmony_ci#include "tools/gpu/GrContextFactory.h" 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_ciusing sk_gpu_test::GrContextFactory; 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_cistatic const int DEV_W = 16, DEV_H = 16; 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ciclass TestDrawable : public SkDrawable { 35cb93a386Sopenharmony_cipublic: 36cb93a386Sopenharmony_ci TestDrawable(const GrVkInterface* interface, GrDirectContext* dContext, 37cb93a386Sopenharmony_ci int32_t width, int32_t height) 38cb93a386Sopenharmony_ci : INHERITED() 39cb93a386Sopenharmony_ci , fInterface(interface) 40cb93a386Sopenharmony_ci , fDContext(dContext) 41cb93a386Sopenharmony_ci , fWidth(width) 42cb93a386Sopenharmony_ci , fHeight(height) {} 43cb93a386Sopenharmony_ci 44cb93a386Sopenharmony_ci ~TestDrawable() override {} 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci class DrawHandlerBasic : public GpuDrawHandler { 47cb93a386Sopenharmony_ci public: 48cb93a386Sopenharmony_ci DrawHandlerBasic(const GrVkInterface* interface, int32_t width, int32_t height) 49cb93a386Sopenharmony_ci : INHERITED() 50cb93a386Sopenharmony_ci , fInterface(interface) 51cb93a386Sopenharmony_ci , fWidth(width) 52cb93a386Sopenharmony_ci , fHeight(height) {} 53cb93a386Sopenharmony_ci ~DrawHandlerBasic() override {} 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci void draw(const GrBackendDrawableInfo& info) override { 56cb93a386Sopenharmony_ci GrVkDrawableInfo vkInfo; 57cb93a386Sopenharmony_ci SkAssertResult(info.getVkDrawableInfo(&vkInfo)); 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci // Clear to Red 60cb93a386Sopenharmony_ci VkClearColorValue vkColor; 61cb93a386Sopenharmony_ci vkColor.float32[0] = 1.0f; // r 62cb93a386Sopenharmony_ci vkColor.float32[1] = 0.0f; // g 63cb93a386Sopenharmony_ci vkColor.float32[2] = 0.0f; // b 64cb93a386Sopenharmony_ci vkColor.float32[3] = 1.0f; // a 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci // Clear right half of render target 67cb93a386Sopenharmony_ci VkClearRect clearRect; 68cb93a386Sopenharmony_ci clearRect.rect.offset = { fWidth / 2, 0 }; 69cb93a386Sopenharmony_ci clearRect.rect.extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight }; 70cb93a386Sopenharmony_ci clearRect.baseArrayLayer = 0; 71cb93a386Sopenharmony_ci clearRect.layerCount = 1; 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci VkClearAttachment attachment; 74cb93a386Sopenharmony_ci attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 75cb93a386Sopenharmony_ci attachment.colorAttachment = vkInfo.fColorAttachmentIndex; 76cb93a386Sopenharmony_ci attachment.clearValue.color = vkColor; 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci GR_VK_CALL(fInterface, CmdClearAttachments(vkInfo.fSecondaryCommandBuffer, 79cb93a386Sopenharmony_ci 1, 80cb93a386Sopenharmony_ci &attachment, 81cb93a386Sopenharmony_ci 1, 82cb93a386Sopenharmony_ci &clearRect)); 83cb93a386Sopenharmony_ci vkInfo.fDrawBounds->offset = { fWidth / 2, 0 }; 84cb93a386Sopenharmony_ci vkInfo.fDrawBounds->extent = { (uint32_t)fWidth / 2, (uint32_t)fHeight }; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci private: 87cb93a386Sopenharmony_ci const GrVkInterface* fInterface; 88cb93a386Sopenharmony_ci int32_t fWidth; 89cb93a386Sopenharmony_ci int32_t fHeight; 90cb93a386Sopenharmony_ci 91cb93a386Sopenharmony_ci using INHERITED = GpuDrawHandler; 92cb93a386Sopenharmony_ci }; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci typedef void (*DrawProc)(TestDrawable*, const SkMatrix&, const SkIRect&, 95cb93a386Sopenharmony_ci const SkImageInfo&, const GrVkDrawableInfo&); 96cb93a386Sopenharmony_ci typedef void (*SubmitProc)(TestDrawable*); 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci // Exercises the exporting of a secondary command buffer from one context and then importing 99cb93a386Sopenharmony_ci // it into a second context. We then draw to the secondary command buffer from the second 100cb93a386Sopenharmony_ci // context. 101cb93a386Sopenharmony_ci class DrawHandlerImport : public GpuDrawHandler { 102cb93a386Sopenharmony_ci public: 103cb93a386Sopenharmony_ci DrawHandlerImport(TestDrawable* td, DrawProc drawProc, SubmitProc submitProc, 104cb93a386Sopenharmony_ci const SkMatrix& matrix, 105cb93a386Sopenharmony_ci const SkIRect& clipBounds, 106cb93a386Sopenharmony_ci const SkImageInfo& bufferInfo) 107cb93a386Sopenharmony_ci : INHERITED() 108cb93a386Sopenharmony_ci , fTestDrawable(td) 109cb93a386Sopenharmony_ci , fDrawProc(drawProc) 110cb93a386Sopenharmony_ci , fSubmitProc(submitProc) 111cb93a386Sopenharmony_ci , fMatrix(matrix) 112cb93a386Sopenharmony_ci , fClipBounds(clipBounds) 113cb93a386Sopenharmony_ci , fBufferInfo(bufferInfo) {} 114cb93a386Sopenharmony_ci ~DrawHandlerImport() override { 115cb93a386Sopenharmony_ci fSubmitProc(fTestDrawable); 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci void draw(const GrBackendDrawableInfo& info) override { 119cb93a386Sopenharmony_ci GrVkDrawableInfo vkInfo; 120cb93a386Sopenharmony_ci SkAssertResult(info.getVkDrawableInfo(&vkInfo)); 121cb93a386Sopenharmony_ci 122cb93a386Sopenharmony_ci fDrawProc(fTestDrawable, fMatrix, fClipBounds, fBufferInfo, vkInfo); 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci private: 125cb93a386Sopenharmony_ci TestDrawable* fTestDrawable; 126cb93a386Sopenharmony_ci DrawProc fDrawProc; 127cb93a386Sopenharmony_ci SubmitProc fSubmitProc; 128cb93a386Sopenharmony_ci const SkMatrix fMatrix; 129cb93a386Sopenharmony_ci const SkIRect fClipBounds; 130cb93a386Sopenharmony_ci const SkImageInfo fBufferInfo; 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci using INHERITED = GpuDrawHandler; 133cb93a386Sopenharmony_ci }; 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci // Helper function to test drawing to a secondary command buffer that we imported into the 136cb93a386Sopenharmony_ci // context using a GrVkSecondaryCBDrawContext. 137cb93a386Sopenharmony_ci static void ImportDraw(TestDrawable* td, const SkMatrix& matrix, const SkIRect& clipBounds, 138cb93a386Sopenharmony_ci const SkImageInfo& bufferInfo, const GrVkDrawableInfo& info) { 139cb93a386Sopenharmony_ci td->fDrawContext = GrVkSecondaryCBDrawContext::Make(td->fDContext, bufferInfo, 140cb93a386Sopenharmony_ci info, nullptr); 141cb93a386Sopenharmony_ci if (!td->fDrawContext) { 142cb93a386Sopenharmony_ci return; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci SkCanvas* canvas = td->fDrawContext->getCanvas(); 146cb93a386Sopenharmony_ci canvas->clipRect(SkRect::Make(clipBounds)); 147cb93a386Sopenharmony_ci canvas->setMatrix(matrix); 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci SkIRect rect = SkIRect::MakeXYWH(td->fWidth/2, 0, td->fWidth/4, td->fHeight); 150cb93a386Sopenharmony_ci SkPaint paint; 151cb93a386Sopenharmony_ci paint.setColor(SK_ColorRED); 152cb93a386Sopenharmony_ci canvas->drawIRect(rect, paint); 153cb93a386Sopenharmony_ci 154cb93a386Sopenharmony_ci // Draw to an offscreen target so that we end up with a mix of "real" secondary command 155cb93a386Sopenharmony_ci // buffers and the imported secondary command buffer. 156cb93a386Sopenharmony_ci sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(td->fDContext, SkBudgeted::kYes, 157cb93a386Sopenharmony_ci bufferInfo); 158cb93a386Sopenharmony_ci surf->getCanvas()->clear(SK_ColorRED); 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci SkRect dstRect = SkRect::MakeXYWH(3*td->fWidth/4, 0, td->fWidth/4, td->fHeight); 161cb93a386Sopenharmony_ci SkRect srcRect = SkRect::MakeIWH(td->fWidth/4, td->fHeight); 162cb93a386Sopenharmony_ci canvas->drawImageRect(surf->makeImageSnapshot(), srcRect, dstRect, SkSamplingOptions(), 163cb93a386Sopenharmony_ci &paint, SkCanvas::kStrict_SrcRectConstraint); 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci td->fDrawContext->flush(); 166cb93a386Sopenharmony_ci } 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci // Helper function to test waiting for the imported secondary command buffer to be submitted on 169cb93a386Sopenharmony_ci // its original context and then cleaning up the GrVkSecondaryCBDrawContext from this context. 170cb93a386Sopenharmony_ci static void ImportSubmitted(TestDrawable* td) { 171cb93a386Sopenharmony_ci // Typical use case here would be to create a fence that we submit to the gpu and then wait 172cb93a386Sopenharmony_ci // on before releasing the GrVkSecondaryCBDrawContext resources. To simulate that for this 173cb93a386Sopenharmony_ci // test (and since we are running single threaded anyways), we will just force a sync of 174cb93a386Sopenharmony_ci // the gpu and cpu here. 175cb93a386Sopenharmony_ci td->fDContext->submit(true); 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci td->fDrawContext->releaseResources(); 178cb93a386Sopenharmony_ci // We release the context here manually to test that we waited long enough before 179cb93a386Sopenharmony_ci // releasing the GrVkSecondaryCBDrawContext. This simulates when a client is able to delete 180cb93a386Sopenharmony_ci // the context it used to imported the secondary command buffer. If we had released the 181cb93a386Sopenharmony_ci // context's resources earlier (before waiting on the gpu above), we would get vulkan 182cb93a386Sopenharmony_ci // validation layer errors saying we freed some vulkan objects while they were still in use 183cb93a386Sopenharmony_ci // on the GPU. 184cb93a386Sopenharmony_ci td->fDContext->releaseResourcesAndAbandonContext(); 185cb93a386Sopenharmony_ci } 186cb93a386Sopenharmony_ci 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci std::unique_ptr<GpuDrawHandler> onSnapGpuDrawHandler(GrBackendApi backendApi, 189cb93a386Sopenharmony_ci const SkMatrix& matrix, 190cb93a386Sopenharmony_ci const SkIRect& clipBounds, 191cb93a386Sopenharmony_ci const SkImageInfo& bufferInfo) override { 192cb93a386Sopenharmony_ci if (backendApi != GrBackendApi::kVulkan) { 193cb93a386Sopenharmony_ci return nullptr; 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci std::unique_ptr<GpuDrawHandler> draw; 196cb93a386Sopenharmony_ci if (fDContext) { 197cb93a386Sopenharmony_ci draw = std::make_unique<DrawHandlerImport>(this, ImportDraw, ImportSubmitted, matrix, 198cb93a386Sopenharmony_ci clipBounds, bufferInfo); 199cb93a386Sopenharmony_ci } else { 200cb93a386Sopenharmony_ci draw = std::make_unique<DrawHandlerBasic>(fInterface, fWidth, fHeight); 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci return draw; 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci 205cb93a386Sopenharmony_ci SkRect onGetBounds() override { 206cb93a386Sopenharmony_ci return SkRect::MakeLTRB(fWidth / 2, 0, fWidth, fHeight); 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci void onDraw(SkCanvas*) override { 210cb93a386Sopenharmony_ci SkASSERT(false); 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci 213cb93a386Sopenharmony_ciprivate: 214cb93a386Sopenharmony_ci const GrVkInterface* fInterface; 215cb93a386Sopenharmony_ci GrDirectContext* fDContext; 216cb93a386Sopenharmony_ci sk_sp<GrVkSecondaryCBDrawContext> fDrawContext; 217cb93a386Sopenharmony_ci int32_t fWidth; 218cb93a386Sopenharmony_ci int32_t fHeight; 219cb93a386Sopenharmony_ci 220cb93a386Sopenharmony_ci using INHERITED = SkDrawable; 221cb93a386Sopenharmony_ci}; 222cb93a386Sopenharmony_ci 223cb93a386Sopenharmony_civoid draw_drawable_test(skiatest::Reporter* reporter, 224cb93a386Sopenharmony_ci GrDirectContext* dContext, 225cb93a386Sopenharmony_ci GrDirectContext* childDContext) { 226cb93a386Sopenharmony_ci GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu()); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci const SkImageInfo ii = SkImageInfo::Make(DEV_W, DEV_H, kRGBA_8888_SkColorType, 229cb93a386Sopenharmony_ci kPremul_SkAlphaType); 230cb93a386Sopenharmony_ci sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(dContext, SkBudgeted::kNo, 231cb93a386Sopenharmony_ci ii, 0, kTopLeft_GrSurfaceOrigin, nullptr)); 232cb93a386Sopenharmony_ci SkCanvas* canvas = surface->getCanvas(); 233cb93a386Sopenharmony_ci canvas->clear(SK_ColorBLUE); 234cb93a386Sopenharmony_ci 235cb93a386Sopenharmony_ci sk_sp<TestDrawable> drawable(new TestDrawable(gpu->vkInterface(), childDContext, DEV_W, DEV_H)); 236cb93a386Sopenharmony_ci canvas->drawDrawable(drawable.get()); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci SkPaint paint; 239cb93a386Sopenharmony_ci paint.setColor(SK_ColorGREEN); 240cb93a386Sopenharmony_ci SkIRect rect = SkIRect::MakeLTRB(0, DEV_H/2, DEV_W, DEV_H); 241cb93a386Sopenharmony_ci canvas->drawIRect(rect, paint); 242cb93a386Sopenharmony_ci 243cb93a386Sopenharmony_ci // read pixels 244cb93a386Sopenharmony_ci SkBitmap bitmap; 245cb93a386Sopenharmony_ci bitmap.allocPixels(ii); 246cb93a386Sopenharmony_ci canvas->readPixels(bitmap, 0, 0); 247cb93a386Sopenharmony_ci 248cb93a386Sopenharmony_ci const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels()); 249cb93a386Sopenharmony_ci bool failureFound = false; 250cb93a386Sopenharmony_ci SkPMColor expectedPixel; 251cb93a386Sopenharmony_ci for (int cy = 0; cy < DEV_H && !failureFound; ++cy) { 252cb93a386Sopenharmony_ci for (int cx = 0; cx < DEV_W && !failureFound; ++cx) { 253cb93a386Sopenharmony_ci SkPMColor canvasPixel = canvasPixels[cy * DEV_W + cx]; 254cb93a386Sopenharmony_ci if (cy < DEV_H / 2) { 255cb93a386Sopenharmony_ci if (cx < DEV_W / 2) { 256cb93a386Sopenharmony_ci expectedPixel = 0xFFFF0000; // Blue 257cb93a386Sopenharmony_ci } else { 258cb93a386Sopenharmony_ci expectedPixel = 0xFF0000FF; // Red 259cb93a386Sopenharmony_ci } 260cb93a386Sopenharmony_ci } else { 261cb93a386Sopenharmony_ci expectedPixel = 0xFF00FF00; // Green 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci if (expectedPixel != canvasPixel) { 264cb93a386Sopenharmony_ci failureFound = true; 265cb93a386Sopenharmony_ci ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x", 266cb93a386Sopenharmony_ci cx, cy, canvasPixel, expectedPixel); 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci } 270cb93a386Sopenharmony_ci} 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ciDEF_GPUTEST_FOR_VULKAN_CONTEXT(VkDrawableTest, reporter, ctxInfo) { 273cb93a386Sopenharmony_ci draw_drawable_test(reporter, ctxInfo.directContext(), nullptr); 274cb93a386Sopenharmony_ci} 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ciDEF_GPUTEST(VkDrawableImportTest, reporter, options) { 277cb93a386Sopenharmony_ci for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) { 278cb93a386Sopenharmony_ci sk_gpu_test::GrContextFactory::ContextType contextType = 279cb93a386Sopenharmony_ci (sk_gpu_test::GrContextFactory::ContextType) typeInt; 280cb93a386Sopenharmony_ci if (contextType != sk_gpu_test::GrContextFactory::kVulkan_ContextType) { 281cb93a386Sopenharmony_ci continue; 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci sk_gpu_test::GrContextFactory factory(options); 284cb93a386Sopenharmony_ci sk_gpu_test::ContextInfo ctxInfo = factory.getContextInfo(contextType); 285cb93a386Sopenharmony_ci skiatest::ReporterContext ctx( 286cb93a386Sopenharmony_ci reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType))); 287cb93a386Sopenharmony_ci if (ctxInfo.directContext()) { 288cb93a386Sopenharmony_ci sk_gpu_test::ContextInfo child = 289cb93a386Sopenharmony_ci factory.getSharedContextInfo(ctxInfo.directContext(), 0); 290cb93a386Sopenharmony_ci if (!child.directContext()) { 291cb93a386Sopenharmony_ci continue; 292cb93a386Sopenharmony_ci } 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci draw_drawable_test(reporter, ctxInfo.directContext(), child.directContext()); 295cb93a386Sopenharmony_ci } 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci} 298cb93a386Sopenharmony_ci 299cb93a386Sopenharmony_ci#endif 300