Add workaround for Adreno copyImageToBuffer calls on Vulkan
BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2328823003 Review-Url: https://codereview.chromium.org/2328823003
This commit is contained in:
parent
f5b7a5490b
commit
6fa0a91e60
@ -16,6 +16,7 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface*
|
||||
VkPhysicalDevice physDev, uint32_t featureFlags, uint32_t extensionFlags)
|
||||
: INHERITED(contextOptions) {
|
||||
fCanUseGLSLForShaderModule = false;
|
||||
fMustDoCopiesFromOrigin = false;
|
||||
|
||||
/**************************************************************************
|
||||
* GrDrawTargetCaps fields
|
||||
@ -66,6 +67,10 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface*
|
||||
// fCanUseGLSLForShaderModule = true;
|
||||
}
|
||||
|
||||
if (kQualcomm_VkVendor == properties.vendorID) {
|
||||
fMustDoCopiesFromOrigin = true;
|
||||
}
|
||||
|
||||
this->applyOptionsOverrides(contextOptions);
|
||||
GrGLSLCaps* glslCaps = static_cast<GrGLSLCaps*>(fShaderCaps.get());
|
||||
glslCaps->applyOptionsOverrides(contextOptions);
|
||||
|
@ -62,6 +62,10 @@ public:
|
||||
return fCanUseGLSLForShaderModule;
|
||||
}
|
||||
|
||||
bool mustDoCopiesFromOrigin() const {
|
||||
return fMustDoCopiesFromOrigin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns both a supported and most prefered stencil format to use in draws.
|
||||
*/
|
||||
@ -72,6 +76,10 @@ public:
|
||||
GrGLSLCaps* glslCaps() const { return reinterpret_cast<GrGLSLCaps*>(fShaderCaps.get()); }
|
||||
|
||||
private:
|
||||
enum VkVendor {
|
||||
kQualcomm_VkVendor = 20803,
|
||||
};
|
||||
|
||||
void init(const GrContextOptions& contextOptions, const GrVkInterface* vkInterface,
|
||||
VkPhysicalDevice device, uint32_t featureFlags, uint32_t extensionFlags);
|
||||
void initGrCaps(const VkPhysicalDeviceProperties&,
|
||||
@ -107,6 +115,10 @@ private:
|
||||
// Tells of if we can pass in straight GLSL string into vkCreateShaderModule
|
||||
bool fCanUseGLSLForShaderModule;
|
||||
|
||||
// On Adreno vulkan, they do not respect the imageOffset parameter at least in
|
||||
// copyImageToBuffer. This flag says that we must do the copy starting from the origin always.
|
||||
bool fMustDoCopiesFromOrigin;
|
||||
|
||||
typedef GrCaps INHERITED;
|
||||
};
|
||||
|
||||
|
@ -1702,27 +1702,41 @@ bool GrVkGpu::onReadPixels(GrSurface* surface,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
false);
|
||||
|
||||
GrVkTransferBuffer* transferBuffer =
|
||||
static_cast<GrVkTransferBuffer*>(this->createBuffer(rowBytes * height,
|
||||
kXferGpuToCpu_GrBufferType,
|
||||
kStream_GrAccessPattern));
|
||||
|
||||
size_t bpp = GrBytesPerPixel(config);
|
||||
size_t tightRowBytes = bpp * width;
|
||||
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(®ion, 0, sizeof(VkBufferImageCopy));
|
||||
|
||||
bool copyFromOrigin = this->vkCaps().mustDoCopiesFromOrigin();
|
||||
if (copyFromOrigin) {
|
||||
region.imageOffset = { 0, 0, 0 };
|
||||
region.imageExtent = { (uint32_t)(left + width),
|
||||
(uint32_t)(flipY ? surface->height() - top : top + height),
|
||||
1
|
||||
};
|
||||
} else {
|
||||
VkOffset3D offset = {
|
||||
left,
|
||||
flipY ? surface->height() - top - height : top,
|
||||
0
|
||||
};
|
||||
region.imageOffset = offset;
|
||||
region.imageExtent = { (uint32_t)width, (uint32_t)height, 1 };
|
||||
}
|
||||
|
||||
size_t transBufferRowBytes = bpp * region.imageExtent.width;
|
||||
GrVkTransferBuffer* transferBuffer =
|
||||
static_cast<GrVkTransferBuffer*>(this->createBuffer(transBufferRowBytes * height,
|
||||
kXferGpuToCpu_GrBufferType,
|
||||
kStream_GrAccessPattern));
|
||||
|
||||
// Copy the image to a buffer so we can map it to cpu memory
|
||||
region.bufferOffset = transferBuffer->offset();
|
||||
region.bufferRowLength = 0; // Forces RowLength to be width. We handle the rowBytes below.
|
||||
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,
|
||||
image,
|
||||
@ -1745,26 +1759,30 @@ bool GrVkGpu::onReadPixels(GrSurface* surface,
|
||||
|
||||
void* mappedMemory = transferBuffer->map();
|
||||
|
||||
size_t tightRowBytes = GrBytesPerPixel(config) * width;
|
||||
if (copyFromOrigin) {
|
||||
uint32_t skipRows = region.imageExtent.height - height;
|
||||
mappedMemory = (char*)mappedMemory + transBufferRowBytes * skipRows + bpp * left;
|
||||
}
|
||||
|
||||
if (flipY) {
|
||||
const char* srcRow = reinterpret_cast<const char*>(mappedMemory);
|
||||
char* dstRow = reinterpret_cast<char*>(buffer)+(height - 1) * rowBytes;
|
||||
for (int y = 0; y < height; y++) {
|
||||
memcpy(dstRow, srcRow, tightRowBytes);
|
||||
srcRow += tightRowBytes;
|
||||
srcRow += transBufferRowBytes;
|
||||
dstRow -= rowBytes;
|
||||
}
|
||||
} else {
|
||||
if (tightRowBytes == rowBytes) {
|
||||
if (transBufferRowBytes == rowBytes) {
|
||||
memcpy(buffer, mappedMemory, rowBytes*height);
|
||||
} else {
|
||||
SkRectMemcpy(buffer, rowBytes, mappedMemory, tightRowBytes, tightRowBytes, height);
|
||||
SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, tightRowBytes,
|
||||
height);
|
||||
}
|
||||
}
|
||||
|
||||
transferBuffer->unmap();
|
||||
transferBuffer->unref();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user