Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(351)

Unified Diff: src/gpu/vk/GrVkGpu.cpp

Issue 1718693002: Add vulkan files into skia repo. (Closed) Base URL: https://skia.googlesource.com/skia.git@merge
Patch Set: fix path Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/vk/GrVkGpu.h ('k') | src/gpu/vk/GrVkImage.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/vk/GrVkGpu.cpp
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef2d0be615d0734a3e03f1469d08b9f81219179d
--- /dev/null
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -0,0 +1,1272 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrVkGpu.h"
+
+#include "GrContextOptions.h"
+#include "GrGeometryProcessor.h"
+#include "GrGpuResourceCacheAccess.h"
+#include "GrPipeline.h"
+#include "GrRenderTargetPriv.h"
+#include "GrSurfacePriv.h"
+#include "GrTexturePriv.h"
+#include "GrVertices.h"
+
+#include "GrVkCommandBuffer.h"
+#include "GrVkImage.h"
+#include "GrVkIndexBuffer.h"
+#include "GrVkMemory.h"
+#include "GrVkPipeline.h"
+#include "GrVkProgram.h"
+#include "GrVkProgramBuilder.h"
+#include "GrVkProgramDesc.h"
+#include "GrVkRenderPass.h"
+#include "GrVkResourceProvider.h"
+#include "GrVkTexture.h"
+#include "GrVkTextureRenderTarget.h"
+#include "GrVkTransferBuffer.h"
+#include "GrVkVertexBuffer.h"
+
+#include "SkConfig8888.h"
+
+#include "vk/GrVkInterface.h"
+
+#define VK_CALL(X) GR_VK_CALL(this->vkInterface(), X)
+#define VK_CALL_RET(RET, X) GR_VK_CALL_RET(this->vkInterface(), RET, X)
+#define VK_CALL_ERRCHECK(X) GR_VK_CALL_ERRCHECK(this->vkInterface(), X)
+
+////////////////////////////////////////////////////////////////////////////////
+// Stuff used to set up a GrVkGpu secrectly for now.
+
+// For now the VkGpuCreate is using the same signature as GL. This is mostly for ease of
+// hiding this code from offical skia. In the end the VkGpuCreate will not take a GrBackendContext
+// and mostly likely would take an optional device and queues to use.
+GrGpu* vk_gpu_create(GrBackendContext backendContext, const GrContextOptions& options,
+ GrContext* context) {
+ // Below is Vulkan setup code that normal would be done by a client, but will do here for now
+ // for testing purposes.
+ VkPhysicalDevice physDev;
+ VkDevice device;
+ VkInstance inst;
+ VkResult err;
+
+ const VkApplicationInfo app_info = {
+ VK_STRUCTURE_TYPE_APPLICATION_INFO, // sType
+ nullptr, // pNext
+ "vktest", // pApplicationName
+ 0, // applicationVersion
+ "vktest", // pEngineName
+ 0, // engineVerison
+ VK_API_VERSION, // apiVersion
+ };
+ const VkInstanceCreateInfo instance_create = {
+ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // flags
+ &app_info, // pApplicationInfo
+ 0, // enabledLayerNameCount
+ nullptr, // ppEnabledLayerNames
+ 0, // enabledExtensionNameCount
+ nullptr, // ppEnabledExtensionNames
+ };
+ err = vkCreateInstance(&instance_create, nullptr, &inst);
+ if (err < 0) {
+ SkDebugf("vkCreateInstanced failed: %d\n", err);
+ SkFAIL("failing");
+ }
+
+ uint32_t gpuCount;
+ err = vkEnumeratePhysicalDevices(inst, &gpuCount, nullptr);
+ if (err) {
+ SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
+ SkFAIL("failing");
+ }
+ SkASSERT(gpuCount > 0);
+ // Just returning the first physical device instead of getting the whole array.
+ gpuCount = 1;
+ err = vkEnumeratePhysicalDevices(inst, &gpuCount, &physDev);
+ if (err) {
+ SkDebugf("vkEnumeratePhysicalDevices failed: %d\n", err);
+ SkFAIL("failing");
+ }
+
+ // query to get the initial queue props size
+ uint32_t queueCount;
+ vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, nullptr);
+ SkASSERT(queueCount >= 1);
+
+ SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
+ // now get the actual queue props
+ VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
+
+ vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueProps);
+
+ // iterate to find the graphics queue
+ uint32_t graphicsQueueIndex = -1;
+ for (uint32_t i = 0; i < queueCount; i++) {
+ if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+ graphicsQueueIndex = i;
+ break;
+ }
+ }
+ SkASSERT(graphicsQueueIndex < queueCount);
+
+ float queuePriorities[1] = { 0.0 };
+ const VkDeviceQueueCreateInfo queueInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // VkDeviceQueueCreateFlags
+ 0, // queueFamilyIndex
+ 1, // queueCount
+ queuePriorities, // pQueuePriorities
+ };
+ const VkDeviceCreateInfo deviceInfo = {
+ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // VkDeviceCreateFlags
+ 1, // queueCreateInfoCount
+ &queueInfo, // pQueueCreateInfos
+ 0, // layerCount
+ nullptr, // ppEnabledLayerNames
+ 0, // extensionCount
+ nullptr, // ppEnabledExtensionNames
+ nullptr // ppEnabledFeatures
+ };
+
+ err = vkCreateDevice(physDev, &deviceInfo, nullptr, &device);
+ if (err) {
+ SkDebugf("CreateDevice failed: %d\n", err);
+ SkFAIL("failing");
+ }
+
+ VkQueue queue;
+ vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
+
+ const VkCommandPoolCreateInfo cmdPoolInfo = {
+ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // sType
+ nullptr, // pNext
+ 0, // CmdPoolCreateFlags
+ graphicsQueueIndex, // queueFamilyIndex
+ };
+
+ VkCommandPool cmdPool;
+ err = vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &cmdPool);
+ if (err) {
+ SkDebugf("CreateCommandPool failed: %d\n", err);
+ SkFAIL("failing");
+ }
+
+ return new GrVkGpu(context, options, physDev, device, queue, cmdPool, inst);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
+ VkPhysicalDevice physDev, VkDevice device, VkQueue queue, VkCommandPool cmdPool,
+ VkInstance inst)
+ : INHERITED(context)
+ , fDevice(device)
+ , fQueue(queue)
+ , fCmdPool(cmdPool)
+ , fResourceProvider(this)
+ , fVkInstance(inst) {
+ fInterface.reset(GrVkCreateInterface(fVkInstance));
+ fCompiler = shaderc_compiler_initialize();
+
+ fVkCaps.reset(new GrVkCaps(options, fInterface, physDev));
+ fCaps.reset(SkRef(fVkCaps.get()));
+
+ fCurrentCmdBuffer = fResourceProvider.createCommandBuffer();
+ SkASSERT(fCurrentCmdBuffer);
+ fCurrentCmdBuffer->begin(this);
+ VK_CALL(GetPhysicalDeviceMemoryProperties(physDev, &fPhysDevMemProps));
+
+}
+
+GrVkGpu::~GrVkGpu() {
+ shaderc_compiler_release(fCompiler);
+ fCurrentCmdBuffer->end(this);
+ fCurrentCmdBuffer->unref(this);
+
+ // wait for all commands to finish
+ VK_CALL(QueueWaitIdle(fQueue));
+
+ // must call this just before we destroy the VkDevice
+ fResourceProvider.destroyResources();
+
+ VK_CALL(DestroyCommandPool(fDevice, fCmdPool, nullptr));
+ VK_CALL(DestroyDevice(fDevice, nullptr));
+ VK_CALL(DestroyInstance(fVkInstance, nullptr));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrVkGpu::submitCommandBuffer(SyncQueue sync) {
+ SkASSERT(fCurrentCmdBuffer);
+ fCurrentCmdBuffer->end(this);
+
+ fCurrentCmdBuffer->submitToQueue(this, fQueue, sync);
+ fResourceProvider.checkCommandBuffers();
+
+ // Release old command buffer and create a new one
+ fCurrentCmdBuffer->unref(this);
+ fCurrentCmdBuffer = fResourceProvider.createCommandBuffer();
+ SkASSERT(fCurrentCmdBuffer);
+
+ fCurrentCmdBuffer->begin(this);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+GrVertexBuffer* GrVkGpu::onCreateVertexBuffer(size_t size, bool dynamic) {
+ return GrVkVertexBuffer::Create(this, size, dynamic);
+}
+
+GrIndexBuffer* GrVkGpu::onCreateIndexBuffer(size_t size, bool dynamic) {
+ return GrVkIndexBuffer::Create(this, size, dynamic);
+}
+
+GrTransferBuffer* GrVkGpu::onCreateTransferBuffer(size_t size, TransferType type) {
+ GrVkBuffer::Type bufferType = kCpuToGpu_TransferType ? GrVkBuffer::kCopyRead_Type
+ : GrVkBuffer::kCopyWrite_Type;
+ return GrVkTransferBuffer::Create(this, size, bufferType);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
+ GrPixelConfig srcConfig, DrawPreference* drawPreference,
+ WritePixelTempDrawInfo* tempDrawInfo) {
+ if (kIndex_8_GrPixelConfig == srcConfig || GrPixelConfigIsCompressed(dstSurface->config())) {
+ return false;
+ }
+
+ // Currently we don't handle draws, so if the caller wants/needs to do a draw we need to fail
+ if (kNoDraw_DrawPreference != *drawPreference) {
+ return false;
+ }
+
+ if (dstSurface->config() != srcConfig) {
+ // TODO: This should fall back to drawing or copying to change config of dstSurface to
+ // match that of srcConfig.
+ return false;
+ }
+
+ return true;
+}
+
+bool GrVkGpu::onWritePixels(GrSurface* surface,
+ int left, int top, int width, int height,
+ GrPixelConfig config, const void* buffer,
+ size_t rowBytes) {
+ GrVkTexture* vkTex = static_cast<GrVkTexture*>(surface->asTexture());
+ if (!vkTex) {
+ return false;
+ }
+
+ // We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels.
+ if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
+ return false;
+ }
+
+ bool success = false;
+ if (GrPixelConfigIsCompressed(vkTex->desc().fConfig)) {
+ // We check that config == desc.fConfig in GrGpu::getWritePixelsInfo()
+ SkASSERT(config == vkTex->desc().fConfig);
+ // TODO: add compressed texture support
+ // delete the following two lines and uncomment the two after that when ready
+ vkTex->unref();
+ return false;
+ //success = this->uploadCompressedTexData(vkTex->desc(), buffer, false, left, top, width,
+ // height);
+ } else {
+ bool linearTiling = vkTex->isLinearTiled();
+ if (linearTiling && VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) {
+ // Need to change the layout to general in order to perform a host write
+ VkImageLayout layout = vkTex->currentLayout();
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_HOST_BIT;
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_HOST_WRITE_BIT;
+ vkTex->setImageLayout(this,
+ VK_IMAGE_LAYOUT_GENERAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+ }
+ success = this->uploadTexData(vkTex, left, top, width, height, config,
+ buffer, rowBytes);
+ }
+
+ if (success) {
+ vkTex->texturePriv().dirtyMipMaps(true);
+ return true;
+ }
+
+ return false;
+}
+
+bool GrVkGpu::uploadTexData(GrVkTexture* tex,
+ int left, int top, int width, int height,
+ GrPixelConfig dataConfig,
+ const void* data,
+ size_t rowBytes) {
+ SkASSERT(data);
+
+ // If we're uploading compressed data then we should be using uploadCompressedTexData
+ SkASSERT(!GrPixelConfigIsCompressed(dataConfig));
+
+ bool linearTiling = tex->isLinearTiled();
+
+ size_t bpp = GrBytesPerPixel(dataConfig);
+
+ const GrSurfaceDesc& desc = tex->desc();
+
+ if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top,
+ &width, &height, &data, &rowBytes)) {
+ return false;
+ }
+ size_t trimRowBytes = width * bpp;
+
+ if (linearTiling) {
+ SkASSERT(VK_IMAGE_LAYOUT_PREINITIALIZED == tex->currentLayout() ||
+ VK_IMAGE_LAYOUT_GENERAL == tex->currentLayout());
+ const VkImageSubresource subres = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, // mipLevel
+ 0, // arraySlice
+ };
+ VkSubresourceLayout layout;
+ VkResult err;
+
+ const GrVkInterface* interface = this->vkInterface();
+
+ GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
+ tex->textureImage(),
+ &subres,
+ &layout));
+
+ int texTop = kBottomLeft_GrSurfaceOrigin == desc.fOrigin ? tex->height() - top - height
+ : top;
+ VkDeviceSize offset = texTop*layout.rowPitch + left*bpp;
+ VkDeviceSize size = height*layout.rowPitch;
+ void* mapPtr;
+ err = GR_VK_CALL(interface, MapMemory(fDevice, tex->textureMemory(), offset, size, 0,
+ &mapPtr));
+ if (err) {
+ return false;
+ }
+
+ if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) {
+ // copy into buffer by rows
+ const char* srcRow = reinterpret_cast<const char*>(data);
+ char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*layout.rowPitch;
+ for (int y = 0; y < height; y++) {
+ memcpy(dstRow, srcRow, trimRowBytes);
+ srcRow += rowBytes;
+ dstRow -= layout.rowPitch;
+ }
+ } else {
+ // If there is no padding on the src (rowBytes) or dst (layout.rowPitch) we can memcpy
+ if (trimRowBytes == rowBytes && trimRowBytes == layout.rowPitch) {
+ memcpy(mapPtr, data, trimRowBytes * height);
+ } else {
+ SkRectMemcpy(mapPtr, layout.rowPitch, data, rowBytes, trimRowBytes, height);
+ }
+ }
+
+ GR_VK_CALL(interface, UnmapMemory(fDevice, tex->textureMemory()));
+ } else {
+ GrVkTransferBuffer* transferBuffer =
+ GrVkTransferBuffer::Create(this, trimRowBytes * height, GrVkBuffer::kCopyRead_Type);
+
+ void* mapPtr = transferBuffer->map();
+
+ if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) {
+ // copy into buffer by rows
+ const char* srcRow = reinterpret_cast<const char*>(data);
+ char* dstRow = reinterpret_cast<char*>(mapPtr)+(height - 1)*trimRowBytes;
+ for (int y = 0; y < height; y++) {
+ memcpy(dstRow, srcRow, trimRowBytes);
+ srcRow += rowBytes;
+ dstRow -= trimRowBytes;
+ }
+ } else {
+ // If there is no padding on the src data rows, we can do a single memcpy
+ if (trimRowBytes == rowBytes) {
+ memcpy(mapPtr, data, trimRowBytes * height);
+ } else {
+ SkRectMemcpy(mapPtr, trimRowBytes, data, rowBytes, trimRowBytes, height);
+ }
+ }
+
+ transferBuffer->unmap();
+
+ // make sure the unmap has finished
+ transferBuffer->addMemoryBarrier(this,
+ VK_ACCESS_HOST_WRITE_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ false);
+
+ // Set up copy region
+ bool flipY = kBottomLeft_GrSurfaceOrigin == tex->origin();
+ VkOffset3D offset = {
+ left,
+ flipY ? tex->height() - top - height : top,
+ 0
+ };
+
+ VkBufferImageCopy region;
+ memset(&region, 0, sizeof(VkBufferImageCopy));
+ region.bufferOffset = 0;
+ region.bufferRowLength = width;
+ region.bufferImageHeight = height;
+ region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ region.imageOffset = offset;
+ region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
+
+ // Change layout of our target so it can be copied to
+ VkImageLayout layout = tex->currentLayout();
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+ tex->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ // Copy the buffer to the image
+ fCurrentCmdBuffer->copyBufferToImage(this,
+ transferBuffer,
+ tex,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &region);
+
+ // Submit the current command buffer to the Queue
+ this->submitCommandBuffer(kSkip_SyncQueue);
+
+ transferBuffer->unref();
+ }
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCycle lifeCycle,
+ const void* srcData, size_t rowBytes) {
+ bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
+
+ VkFormat pixelFormat;
+ if (!GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat)) {
+ return nullptr;
+ }
+
+ if (!fVkCaps->isConfigTexturable(desc.fConfig)) {
+ return nullptr;
+ }
+
+ bool linearTiling = false;
+ if (SkToBool(desc.fFlags & kZeroCopy_GrSurfaceFlag)) {
+ if (fVkCaps->isConfigTexurableLinearly(desc.fConfig) &&
+ (!renderTarget || fVkCaps->isConfigRenderableLinearly(desc.fConfig, false))) {
+ linearTiling = true;
+ } else {
+ return nullptr;
+ }
+ }
+
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
+ if (renderTarget) {
+ usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ }
+
+ // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
+ // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
+ // will be using this texture in some copy or not. Also this assumes, as is the current case,
+ // that all render targets in vulkan are also texutres. If we change this practice of setting
+ // both bits, we must make sure to set the destination bit if we are uploading srcData to the
+ // texture.
+ usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ VkFlags memProps = (srcData && linearTiling) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
+ // requested, this ImageDesc describes the resolved texutre. Therefore we always have samples set
+ // to 1.
+ GrVkImage::ImageDesc imageDesc;
+ imageDesc.fImageType = VK_IMAGE_TYPE_2D;
+ imageDesc.fFormat = pixelFormat;
+ imageDesc.fWidth = desc.fWidth;
+ imageDesc.fHeight = desc.fHeight;
+ imageDesc.fLevels = 1;
+ imageDesc.fSamples = 1;
+ imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
+ imageDesc.fUsageFlags = usageFlags;
+ imageDesc.fMemProps = memProps;
+
+ GrVkTexture* tex;
+ if (renderTarget) {
+ tex = GrVkTextureRenderTarget::CreateNewTextureRenderTarget(this, desc, lifeCycle,
+ imageDesc);
+ } else {
+ tex = GrVkTexture::CreateNewTexture(this, desc, lifeCycle, imageDesc);
+ }
+
+ if (!tex) {
+ return nullptr;
+ }
+
+ if (srcData) {
+ if (!this->uploadTexData(tex, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig, srcData,
+ rowBytes)) {
+ tex->unref();
+ return nullptr;
+ }
+ }
+
+ return tex;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static GrSurfaceOrigin resolve_origin(GrSurfaceOrigin origin) {
+ // By default, all textures in Vk use TopLeft
+ if (kDefault_GrSurfaceOrigin == origin) {
+ return kTopLeft_GrSurfaceOrigin;
+ } else {
+ return origin;
+ }
+}
+
+GrTexture* GrVkGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
+ GrWrapOwnership ownership) {
+ VkFormat format;
+ if (!GrPixelConfigToVkFormat(desc.fConfig, &format)) {
+ return nullptr;
+ }
+
+ if (0 == desc.fTextureHandle) {
+ return nullptr;
+ }
+
+ int maxSize = this->caps()->maxTextureSize();
+ if (desc.fWidth > maxSize || desc.fHeight > maxSize) {
+ return nullptr;
+ }
+
+ // TODO: determine what format Chrome will actually send us and turn it into a Resource
+ GrVkImage::Resource* imageRsrc = reinterpret_cast<GrVkImage::Resource*>(desc.fTextureHandle);
+
+ GrGpuResource::LifeCycle lifeCycle;
+ switch (ownership) {
+ case kAdopt_GrWrapOwnership:
+ lifeCycle = GrGpuResource::kAdopted_LifeCycle;
+ break;
+ case kBorrow_GrWrapOwnership:
+ lifeCycle = GrGpuResource::kBorrowed_LifeCycle;
+ break;
+ }
+
+ GrSurfaceDesc surfDesc;
+ // next line relies on GrBackendTextureDesc's flags matching GrTexture's
+ surfDesc.fFlags = (GrSurfaceFlags)desc.fFlags;
+ surfDesc.fWidth = desc.fWidth;
+ surfDesc.fHeight = desc.fHeight;
+ surfDesc.fConfig = desc.fConfig;
+ surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount());
+ bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
+ // In GL, Chrome assumes all textures are BottomLeft
+ // In VK, we don't have this restriction
+ surfDesc.fOrigin = resolve_origin(desc.fOrigin);
+
+ GrVkTexture* texture = nullptr;
+ if (renderTarget) {
+ texture = GrVkTextureRenderTarget::CreateWrappedTextureRenderTarget(this, surfDesc,
+ lifeCycle, format,
+ imageRsrc);
+ } else {
+ texture = GrVkTexture::CreateWrappedTexture(this, surfDesc, lifeCycle, format, imageRsrc);
+ }
+ if (!texture) {
+ return nullptr;
+ }
+
+ return texture;
+}
+
+GrRenderTarget* GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTargetDesc& wrapDesc,
+ GrWrapOwnership ownership) {
+
+ // TODO: determine what format Chrome will actually send us and turn it into a Resource
+ GrVkImage::Resource* imageRsrc =
+ reinterpret_cast<GrVkImage::Resource*>(wrapDesc.fRenderTargetHandle);
+
+ GrGpuResource::LifeCycle lifeCycle;
+ switch (ownership) {
+ case kAdopt_GrWrapOwnership:
+ lifeCycle = GrGpuResource::kAdopted_LifeCycle;
+ break;
+ case kBorrow_GrWrapOwnership:
+ lifeCycle = GrGpuResource::kBorrowed_LifeCycle;
+ break;
+ }
+
+ GrSurfaceDesc desc;
+ desc.fConfig = wrapDesc.fConfig;
+ desc.fFlags = kCheckAllocation_GrSurfaceFlag;
+ desc.fWidth = wrapDesc.fWidth;
+ desc.fHeight = wrapDesc.fHeight;
+ desc.fSampleCnt = SkTMin(wrapDesc.fSampleCnt, this->caps()->maxSampleCount());
+
+ desc.fOrigin = resolve_origin(wrapDesc.fOrigin);
+
+ GrVkRenderTarget* tgt = GrVkRenderTarget::CreateWrappedRenderTarget(this, desc,
+ lifeCycle, imageRsrc);
+ if (tgt && wrapDesc.fStencilBits) {
+ if (!createStencilAttachmentForRenderTarget(tgt, desc.fWidth, desc.fHeight)) {
+ tgt->unref();
+ return nullptr;
+ }
+ }
+ return tgt;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrVkGpu::bindGeometry(const GrPrimitiveProcessor& primProc,
+ const GrNonInstancedVertices& vertices) {
+ GrVkVertexBuffer* vbuf;
+ vbuf = (GrVkVertexBuffer*)vertices.vertexBuffer();
+ SkASSERT(vbuf);
+ SkASSERT(!vbuf->isMapped());
+
+ vbuf->addMemoryBarrier(this,
+ VK_ACCESS_HOST_WRITE_BIT,
+ VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT,
+ VK_PIPELINE_STAGE_HOST_BIT,
+ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
+ false);
+
+ fCurrentCmdBuffer->bindVertexBuffer(this, vbuf);
+
+ if (vertices.isIndexed()) {
+ GrVkIndexBuffer* ibuf = (GrVkIndexBuffer*)vertices.indexBuffer();
+ SkASSERT(ibuf);
+ SkASSERT(!ibuf->isMapped());
+
+ ibuf->addMemoryBarrier(this,
+ VK_ACCESS_HOST_WRITE_BIT,
+ VK_ACCESS_INDEX_READ_BIT,
+ VK_PIPELINE_STAGE_HOST_BIT,
+ VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
+ false);
+
+ fCurrentCmdBuffer->bindIndexBuffer(this, ibuf);
+ }
+}
+
+void GrVkGpu::buildProgramDesc(GrProgramDesc* desc,
+ const GrPrimitiveProcessor& primProc,
+ const GrPipeline& pipeline) const {
+ if (!GrVkProgramDescBuilder::Build(desc, primProc, pipeline, *this->vkCaps().glslCaps())) {
+ SkDEBUGFAIL("Failed to generate GL program descriptor");
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrStencilAttachment* GrVkGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
+ int width,
+ int height) {
+ SkASSERT(rt->asTexture());
+ SkASSERT(width >= rt->width());
+ SkASSERT(height >= rt->height());
+
+ int samples = rt->numStencilSamples();
+
+ SkASSERT(this->vkCaps().stencilFormats().count());
+ const GrVkCaps::StencilFormat& sFmt = this->vkCaps().stencilFormats()[0];
+
+ GrVkStencilAttachment* stencil(GrVkStencilAttachment::Create(this,
+ GrGpuResource::kCached_LifeCycle,
+ width,
+ height,
+ samples,
+ sFmt));
+ fStats.incStencilAttachmentCreates();
+ return stencil;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrBackendObject GrVkGpu::createTestingOnlyBackendTexture(void* srcData, int w, int h,
+ GrPixelConfig config) {
+
+ VkFormat pixelFormat;
+ if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
+ return 0;
+ }
+
+ bool linearTiling = false;
+ if (!fVkCaps->isConfigTexturable(config)) {
+ return 0;
+ }
+
+ if (fVkCaps->isConfigTexurableLinearly(config)) {
+ linearTiling = true;
+ }
+
+ // Currently this is not supported since it requires a copy which has not yet been implemented.
+ if (srcData && !linearTiling) {
+ return 0;
+ }
+
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
+ usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ usageFlags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+ VkFlags memProps = (srcData && linearTiling) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT :
+ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+
+ // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
+ // requested, this ImageDesc describes the resolved texutre. Therefore we always have samples set
+ // to 1.
+ GrVkImage::ImageDesc imageDesc;
+ imageDesc.fImageType = VK_IMAGE_TYPE_2D;
+ imageDesc.fFormat = pixelFormat;
+ imageDesc.fWidth = w;
+ imageDesc.fHeight = h;
+ imageDesc.fLevels = 1;
+ imageDesc.fSamples = 1;
+ imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
+ imageDesc.fUsageFlags = usageFlags;
+ imageDesc.fMemProps = memProps;
+
+ const GrVkImage::Resource* imageRsrc = GrVkImage::CreateResource(this, imageDesc);
+ if (!imageRsrc) {
+ return 0;
+ }
+
+ if (srcData) {
+ if (linearTiling) {
+ const VkImageSubresource subres = {
+ VK_IMAGE_ASPECT_COLOR_BIT,
+ 0, // mipLevel
+ 0, // arraySlice
+ };
+ VkSubresourceLayout layout;
+ VkResult err;
+
+ const GrVkInterface* interface = this->vkInterface();
+
+ GR_VK_CALL(interface, GetImageSubresourceLayout(fDevice,
+ imageRsrc->fImage,
+ &subres,
+ &layout));
+
+ void* mapPtr;
+ err = GR_VK_CALL(interface, MapMemory(fDevice,
+ imageRsrc->fAlloc,
+ 0,
+ layout.rowPitch * h,
+ 0,
+ &mapPtr));
+ if (err) {
+ imageRsrc->unref(this);
+ return 0;
+ }
+
+ size_t bpp = GrBytesPerPixel(config);
+ size_t rowCopyBytes = bpp * w;
+ // If there is no padding on dst (layout.rowPitch) we can do a single memcopy.
+ // This assumes the srcData comes in with no padding.
+ if (rowCopyBytes == layout.rowPitch) {
+ memcpy(mapPtr, srcData, rowCopyBytes * h);
+ } else {
+ SkRectMemcpy(mapPtr, layout.rowPitch, srcData, w, rowCopyBytes, h);
+ }
+ GR_VK_CALL(interface, UnmapMemory(fDevice, imageRsrc->fAlloc));
+ } else {
+ // TODO: Add support for copying to optimal tiling
+ SkASSERT(false);
+ }
+ }
+
+ return (GrBackendObject)imageRsrc;
+}
+
+bool GrVkGpu::isTestingOnlyBackendTexture(GrBackendObject id) const {
+ GrVkImage::Resource* backend = reinterpret_cast<GrVkImage::Resource*>(id);
+
+ if (backend && backend->fImage && backend->fAlloc) {
+ VkMemoryRequirements req;
+ memset(&req, 0, sizeof(req));
+ GR_VK_CALL(this->vkInterface(), GetImageMemoryRequirements(fDevice,
+ backend->fImage,
+ &req));
+ // TODO: find a better check
+ // This will probably fail with a different driver
+ return (req.size > 0) && (req.size <= 8192 * 8192);
+ }
+
+ return false;
+}
+
+void GrVkGpu::deleteTestingOnlyBackendTexture(GrBackendObject id, bool abandon) {
+ GrVkImage::Resource* backend = reinterpret_cast<GrVkImage::Resource*>(id);
+
+ if (backend) {
+ if (!abandon) {
+ backend->unref(this);
+ } else {
+ backend->unrefAndAbandon();
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrVkGpu::addMemoryBarrier(VkPipelineStageFlags srcStageMask,
+ VkPipelineStageFlags dstStageMask,
+ bool byRegion,
+ VkMemoryBarrier* barrier) const {
+ SkASSERT(fCurrentCmdBuffer);
+ fCurrentCmdBuffer->pipelineBarrier(this,
+ srcStageMask,
+ dstStageMask,
+ byRegion,
+ GrVkCommandBuffer::kMemory_BarrierType,
+ barrier);
+}
+
+void GrVkGpu::addBufferMemoryBarrier(VkPipelineStageFlags srcStageMask,
+ VkPipelineStageFlags dstStageMask,
+ bool byRegion,
+ VkBufferMemoryBarrier* barrier) const {
+ SkASSERT(fCurrentCmdBuffer);
+ fCurrentCmdBuffer->pipelineBarrier(this,
+ srcStageMask,
+ dstStageMask,
+ byRegion,
+ GrVkCommandBuffer::kBufferMemory_BarrierType,
+ barrier);
+}
+
+void GrVkGpu::addImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
+ VkPipelineStageFlags dstStageMask,
+ bool byRegion,
+ VkImageMemoryBarrier* barrier) const {
+ SkASSERT(fCurrentCmdBuffer);
+ fCurrentCmdBuffer->pipelineBarrier(this,
+ srcStageMask,
+ dstStageMask,
+ byRegion,
+ GrVkCommandBuffer::kImageMemory_BarrierType,
+ barrier);
+}
+
+void GrVkGpu::finishDrawTarget() {
+ // Submit the current command buffer to the Queue
+ this->submitCommandBuffer(kSkip_SyncQueue);
+}
+
+void GrVkGpu::onClear(GrRenderTarget* target, const SkIRect& rect, GrColor color) {
+ // parent class should never let us get here with no RT
+ SkASSERT(target);
+
+ VkClearColorValue vkColor;
+ GrColorToRGBAFloat(color, vkColor.float32);
+
+ GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(target);
+ VkImageLayout origDstLayout = vkRT->currentLayout();
+
+ if (rect.width() != target->width() || rect.height() != target->height()) {
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ VkPipelineStageFlags srcStageMask =
+ GrVkMemory::LayoutToPipelineStageFlags(vkRT->currentLayout());
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ vkRT->setImageLayout(this,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ VkClearRect clearRect;
+ clearRect.rect.offset = { rect.fLeft, rect.fTop };
+ clearRect.rect.extent = { (uint32_t)rect.width(), (uint32_t)rect.height() };
+ clearRect.baseArrayLayer = 0;
+ clearRect.layerCount = 1;
+
+
+
+ const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
+ SkASSERT(renderPass);
+ fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
+
+ uint32_t colorIndex;
+ SkAssertResult(renderPass->colorAttachmentIndex(&colorIndex));
+
+ VkClearAttachment attachment;
+ attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ attachment.colorAttachment = colorIndex;
+ attachment.clearValue.color = vkColor;
+
+ fCurrentCmdBuffer->clearAttachments(this, 1, &attachment, 1, &clearRect);
+ fCurrentCmdBuffer->endRenderPass(this);
+ return;
+ }
+
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
+ VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ vkRT->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+
+ VkImageSubresourceRange subRange;
+ memset(&subRange, 0, sizeof(VkImageSubresourceRange));
+ subRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ subRange.baseMipLevel = 0;
+ subRange.levelCount = 1;
+ subRange.baseArrayLayer = 0;
+ subRange.layerCount = 1;
+
+ // In the future we may not actually be doing this type of clear at all. If we are inside a
+ // render pass or doing a non full clear then we will use CmdClearColorAttachment. The more
+ // common use case will be clearing an attachment at the start of a render pass, in which case
+ // we will use the clear load ops.
+ fCurrentCmdBuffer->clearColorImage(this,
+ vkRT,
+ &vkColor,
+ 1, &subRange);
+}
+
+inline bool can_copy_image(const GrSurface* dst,
+ const GrSurface* src,
+ const GrVkGpu* gpu) {
+ if (src->asTexture() &&
+ dst->asTexture() &&
+ src->origin() == dst->origin() &&
+ src->config() == dst->config()) {
+ return true;
+ }
+
+ // How does msaa play into this? If a VkTexture is multisampled, are we copying the multisampled
+ // or the resolved image here?
+
+ return false;
+}
+
+void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint) {
+ SkASSERT(can_copy_image(dst, src, this));
+
+ // Insert memory barriers to switch src and dst to transfer_source and transfer_dst layouts
+ GrVkTexture* dstTex = static_cast<GrVkTexture*>(dst->asTexture());
+ GrVkTexture* srcTex = static_cast<GrVkTexture*>(src->asTexture());
+
+ VkImageLayout origDstLayout = dstTex->currentLayout();
+ VkImageLayout origSrcLayout = srcTex->currentLayout();
+
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origDstLayout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ // These flags are for flushing/invalidating caches and for the dst image it doesn't matter if
+ // the cache is flushed since it is only being written to.
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origDstLayout);;
+ VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
+
+ dstTex->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(origSrcLayout);
+ dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+
+ srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(origSrcLayout);
+ dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+
+ srcTex->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ // Flip rect if necessary
+ SkIRect srcVkRect = srcRect;
+ int32_t dstY = dstPoint.fY;
+
+ if (kBottomLeft_GrSurfaceOrigin == src->origin()) {
+ SkASSERT(kBottomLeft_GrSurfaceOrigin == dst->origin());
+ srcVkRect.fTop = src->height() - srcRect.fBottom;
+ srcVkRect.fBottom = src->height() - srcRect.fTop;
+ dstY = dst->height() - dstPoint.fY - srcVkRect.height();
+ }
+
+ VkImageCopy copyRegion;
+ memset(&copyRegion, 0, sizeof(VkImageCopy));
+ copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.srcOffset = { srcVkRect.fLeft, srcVkRect.fTop, 0 };
+ copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ copyRegion.dstOffset = { dstPoint.fX, dstY, 0 };
+ copyRegion.extent = { (uint32_t)srcVkRect.width(), (uint32_t)srcVkRect.height(), 0 };
+
+ fCurrentCmdBuffer->copyImage(this,
+ srcTex,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ dstTex,
+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+ 1,
+ &copyRegion);
+}
+
+inline bool can_copy_as_draw(const GrSurface* dst,
+ const GrSurface* src,
+ const GrVkGpu* gpu) {
+ return false;
+}
+
+void GrVkGpu::copySurfaceAsDraw(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint) {
+ SkASSERT(false);
+}
+
+bool GrVkGpu::onCopySurface(GrSurface* dst,
+ GrSurface* src,
+ const SkIRect& srcRect,
+ const SkIPoint& dstPoint) {
+ if (can_copy_image(dst, src, this)) {
+ this->copySurfaceAsCopyImage(dst, src, srcRect, dstPoint);
+ return true;
+ }
+
+ if (can_copy_as_draw(dst, src, this)) {
+ this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
+ return true;
+ }
+
+ return false;
+}
+
+bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
+ GrPixelConfig readConfig, DrawPreference* drawPreference,
+ ReadPixelTempDrawInfo* tempDrawInfo) {
+ // Currently we don't handle draws, so if the caller wants/needs to do a draw we need to fail
+ if (kNoDraw_DrawPreference != *drawPreference) {
+ return false;
+ }
+
+ if (srcSurface->config() != readConfig) {
+ // TODO: This should fall back to drawing or copying to change config of srcSurface to match
+ // that of readConfig.
+ return false;
+ }
+
+ return true;
+}
+
+bool GrVkGpu::onReadPixels(GrSurface* surface,
+ int left, int top, int width, int height,
+ GrPixelConfig config,
+ void* buffer,
+ size_t rowBytes) {
+ VkFormat pixelFormat;
+ if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
+ return false;
+ }
+
+ GrVkTexture* tgt = static_cast<GrVkTexture*>(surface->asTexture());
+ if (!tgt) {
+ return false;
+ }
+
+ // Change layout of our target so it can be used as copy
+ VkImageLayout layout = tgt->currentLayout();
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
+ tgt->setImageLayout(this,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ GrVkTransferBuffer* transferBuffer =
+ reinterpret_cast<GrVkTransferBuffer*>(this->createTransferBuffer(rowBytes * height,
+ kGpuToCpu_TransferType));
+
+ bool flipY = kBottomLeft_GrSurfaceOrigin == surface->origin();
+ VkOffset3D offset = {
+ left,
+ flipY ? surface->height() - top - height : top,
+ 0
+ };
+
+ // Copy the image to a buffer so we can map it to cpu memory
+ VkBufferImageCopy region;
+ memset(&region, 0, sizeof(VkBufferImageCopy));
+ region.bufferOffset = 0;
+ region.bufferRowLength = 0; // Forces RowLength to be imageExtent.width
+ region.bufferImageHeight = 0; // Forces height to be tightly packed. Only useful for 3d images.
+ region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
+ region.imageOffset = offset;
+ region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
+
+ fCurrentCmdBuffer->copyImageToBuffer(this,
+ tgt,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ transferBuffer,
+ 1,
+ &region);
+
+ // make sure the copy to buffer has finished
+ transferBuffer->addMemoryBarrier(this,
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_ACCESS_HOST_READ_BIT,
+ VK_PIPELINE_STAGE_TRANSFER_BIT,
+ VK_PIPELINE_STAGE_HOST_BIT,
+ false);
+
+ // We need to submit the current command buffer to the Queue and make sure it finishes before
+ // we can copy the data out of the buffer.
+ this->submitCommandBuffer(kForce_SyncQueue);
+
+ void* mappedMemory = transferBuffer->map();
+
+ memcpy(buffer, mappedMemory, rowBytes*height);
+
+ transferBuffer->unmap();
+ transferBuffer->unref();
+
+ if (flipY) {
+ SkAutoSMalloc<32 * sizeof(GrColor)> scratch;
+ size_t tightRowBytes = GrBytesPerPixel(config) * width;
+ scratch.reset(tightRowBytes);
+ void* tmpRow = scratch.get();
+ // flip y in-place by rows
+ const int halfY = height >> 1;
+ char* top = reinterpret_cast<char*>(buffer);
+ char* bottom = top + (height - 1) * rowBytes;
+ for (int y = 0; y < halfY; y++) {
+ memcpy(tmpRow, top, tightRowBytes);
+ memcpy(top, bottom, tightRowBytes);
+ memcpy(bottom, tmpRow, tightRowBytes);
+ top += rowBytes;
+ bottom -= rowBytes;
+ }
+ }
+
+ return true;
+}
+
+void GrVkGpu::onDraw(const DrawArgs& args, const GrNonInstancedVertices& vertices) {
+ GrRenderTarget* rt = args.fPipeline->getRenderTarget();
+ GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt);
+ const GrVkRenderPass* renderPass = vkRT->simpleRenderPass();
+ SkASSERT(renderPass);
+
+
+ GrVkProgram* program = GrVkProgramBuilder::CreateProgram(this, args,
+ vertices.primitiveType(),
+ *renderPass);
+
+ if (!program) {
+ return;
+ }
+
+ program->setData(this, *args.fPrimitiveProcessor, *args.fPipeline);
+
+ fCurrentCmdBuffer->beginRenderPass(this, renderPass, *vkRT);
+
+ program->bind(this, fCurrentCmdBuffer);
+
+ this->bindGeometry(*args.fPrimitiveProcessor, vertices);
+
+ // Change layout of our render target so it can be used as the color attachment
+ VkImageLayout layout = vkRT->currentLayout();
+ // Our color attachment is purely a destination and won't be read so don't need to flush or
+ // invalidate any caches
+ VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
+ VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+ VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
+ VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ vkRT->setImageLayout(this,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ srcAccessMask,
+ dstAccessMask,
+ srcStageMask,
+ dstStageMask,
+ false);
+
+ if (vertices.isIndexed()) {
+ fCurrentCmdBuffer->drawIndexed(this,
+ vertices.indexCount(),
+ 1,
+ vertices.startIndex(),
+ vertices.startVertex(),
+ 0);
+ } else {
+ fCurrentCmdBuffer->draw(this, vertices.vertexCount(), 1, vertices.startVertex(), 0);
+ }
+
+ fCurrentCmdBuffer->endRenderPass(this);
+
+ // Technically we don't have to call this here (since there is a safety check in program:setData
+ // but this will allow for quicker freeing of resources if the program sits in a cache for a
+ // while.
+ program->freeTempResources(this);
+ // This free will go away once we setup a program cache, and then the cache will be responsible
+ // for call freeGpuResources.
+ program->freeGPUResources(this);
+ program->unref();
+
+#if SWAP_PER_DRAW
+ glFlush();
+#if defined(SK_BUILD_FOR_MAC)
+ aglSwapBuffers(aglGetCurrentContext());
+ int set_a_break_pt_here = 9;
+ aglSwapBuffers(aglGetCurrentContext());
+#elif defined(SK_BUILD_FOR_WIN32)
+ SwapBuf();
+ int set_a_break_pt_here = 9;
+ SwapBuf();
+#endif
+#endif
+}
+
« no previous file with comments | « src/gpu/vk/GrVkGpu.h ('k') | src/gpu/vk/GrVkImage.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698