Index: src/gpu/vk/GrVkGpu.cpp |
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp |
index 33b53b1bcd76b257ffa28f6e5cfa6ec5fb216560..71782777a55838c8cf97ff9a94ffa4f39c4d90e9 100644 |
--- a/src/gpu/vk/GrVkGpu.cpp |
+++ b/src/gpu/vk/GrVkGpu.cpp |
@@ -283,9 +283,10 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, |
success = this->uploadTexDataLinear(vkTex, left, top, width, height, config, |
texels.begin()->fPixels, texels.begin()->fRowBytes); |
} else { |
- int mipLevels = texels.count(); |
- if (vkTex->texturePriv().maxMipMapLevel() != mipLevels) { |
- if (!vkTex->reallocForMipmap(this, mipLevels)) { |
+ int newMipLevels = texels.count(); |
+ int currentMipLevels = vkTex->texturePriv().maxMipMapLevel(); |
+ if ((currentMipLevels || newMipLevels != 1) && newMipLevels != currentMipLevels) { |
+ if (!vkTex->reallocForMipmap(this, newMipLevels)) { |
return false; |
} |
} |
@@ -389,36 +390,45 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, |
size_t bpp = GrBytesPerPixel(dataConfig); |
// texels is const. |
- // But we may need to adjust the fPixels ptr based on the copyRect. |
- // In this case we need to make a non-const shallow copy of texels. |
- const SkTArray<GrMipLevel>* texelsPtr = &texels; |
- SkTArray<GrMipLevel> texelsCopy; |
- if (0 != left || 0 != top || width != tex->width() || height != tex->height()) { |
- texelsCopy = texels; |
+ // But we may need to adjust the fPixels ptr based on the copyRect, or fRowBytes. |
+ // Because of this we need to make a non-const shallow copy of texels. |
+ SkTArray<GrMipLevel> texelsShallowCopy(texels); |
- SkASSERT(1 == texels.count()); |
- SkASSERT(texelsCopy[0].fPixels); |
- |
- if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top, |
- &width, &height, &texelsCopy[0].fPixels, |
- &texelsCopy[0].fRowBytes)) { |
- return false; |
- } |
- |
- texelsPtr = &texelsCopy; |
+ for (int currentMipLevel = texelsShallowCopy.count() - 1; currentMipLevel >= 0; |
+ currentMipLevel--) { |
+ SkASSERT(texelsShallowCopy[currentMipLevel].fPixels); |
} |
// Determine whether we need to flip when we copy into the buffer |
- bool flipY = (kBottomLeft_GrSurfaceOrigin == desc.fOrigin && !texelsPtr->empty()); |
+ bool flipY = (kBottomLeft_GrSurfaceOrigin == desc.fOrigin && !texelsShallowCopy.empty()); |
+ // adjust any params (left, top, currentWidth, currentHeight |
// find the combined size of all the mip levels and the relative offset of |
// each into the collective buffer |
- size_t combinedBufferSize = 0; |
- SkTArray<size_t> individualMipOffsets(texelsPtr->count()); |
- for (int currentMipLevel = 0; currentMipLevel < texelsPtr->count(); currentMipLevel++) { |
- int twoToTheMipLevel = 1 << currentMipLevel; |
- int currentWidth = SkTMax(1, width / twoToTheMipLevel); |
- int currentHeight = SkTMax(1, height / twoToTheMipLevel); |
+ // Do the first level separately because we may need to adjust width and height |
+ // (for the non-mipped case). |
+ if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top, |
+ &width, |
+ &height, |
+ &texelsShallowCopy[0].fPixels, |
+ &texelsShallowCopy[0].fRowBytes)) { |
+ return false; |
+ } |
+ SkTArray<size_t> individualMipOffsets(texelsShallowCopy.count()); |
+ individualMipOffsets.push_back(0); |
+ size_t combinedBufferSize = width * bpp * height; |
+ int currentWidth = width; |
+ int currentHeight = height; |
+ for (int currentMipLevel = 1; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) { |
+ currentWidth = SkTMax(1, currentWidth/2); |
+ currentHeight = SkTMax(1, currentHeight/2); |
+ if (!GrSurfacePriv::AdjustWritePixelParams(desc.fWidth, desc.fHeight, bpp, &left, &top, |
+ ¤tWidth, |
+ ¤tHeight, |
+ &texelsShallowCopy[currentMipLevel].fPixels, |
+ &texelsShallowCopy[currentMipLevel].fRowBytes)) { |
+ return false; |
+ } |
const size_t trimmedSize = currentWidth * bpp * currentHeight; |
individualMipOffsets.push_back(combinedBufferSize); |
combinedBufferSize += trimmedSize; |
@@ -429,18 +439,17 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, |
GrVkTransferBuffer::Create(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type); |
char* buffer = (char*) transferBuffer->map(); |
- SkTArray<VkBufferImageCopy> regions(texelsPtr->count()); |
+ SkTArray<VkBufferImageCopy> regions(texelsShallowCopy.count()); |
- for (int currentMipLevel = 0; currentMipLevel < texelsPtr->count(); currentMipLevel++) { |
- int twoToTheMipLevel = 1 << currentMipLevel; |
- int currentWidth = SkTMax(1, width / twoToTheMipLevel); |
- int currentHeight = SkTMax(1, height / twoToTheMipLevel); |
+ currentWidth = width; |
+ currentHeight = height; |
+ for (int currentMipLevel = 0; currentMipLevel < texelsShallowCopy.count(); currentMipLevel++) { |
const size_t trimRowBytes = currentWidth * bpp; |
- const size_t rowBytes = (*texelsPtr)[currentMipLevel].fRowBytes; |
+ const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes; |
// copy data into the buffer, skipping the trailing bytes |
char* dst = buffer + individualMipOffsets[currentMipLevel]; |
- const char* src = (const char*)(*texelsPtr)[currentMipLevel].fPixels; |
+ const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels; |
if (flipY) { |
src += (currentHeight - 1) * rowBytes; |
for (int y = 0; y < currentHeight; y++) { |
@@ -460,8 +469,11 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, |
region.bufferRowLength = currentWidth; |
region.bufferImageHeight = currentHeight; |
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 }; |
- region.imageOffset = { left, top, 0 }; |
+ region.imageOffset = { left, flipY ? tex->height() - top - currentHeight : top, 0 }; |
region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 }; |
+ |
+ currentWidth = SkTMax(1, currentWidth/2); |
+ currentHeight = SkTMax(1, currentHeight/2); |
} |
transferBuffer->unmap(); |
@@ -553,12 +565,13 @@ GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budget |
// This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is |
// requested, this ImageDesc describes the resolved texture. Therefore we always have samples set |
// to 1. |
+ int mipLevels = texels.empty() ? 1 : texels.count(); |
GrVkImage::ImageDesc imageDesc; |
imageDesc.fImageType = VK_IMAGE_TYPE_2D; |
imageDesc.fFormat = pixelFormat; |
imageDesc.fWidth = desc.fWidth; |
imageDesc.fHeight = desc.fHeight; |
- imageDesc.fLevels = linearTiling ? 1 : texels.count(); |
+ imageDesc.fLevels = linearTiling ? 1 : mipLevels; |
imageDesc.fSamples = 1; |
imageDesc.fImageTiling = linearTiling ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL; |
imageDesc.fUsageFlags = usageFlags; |