Skip to content

Commit

Permalink
Add api on GrContext to update the data of GrBackendTextures.
Browse files Browse the repository at this point in the history
Change-Id: I680f12bf58fc7b66a6b2f3fa4c4723ae84d3f949
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/288555
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
  • Loading branch information
egdaniel authored and Skia Commit-Bot committed May 8, 2020
1 parent 2887d35 commit ac09f7c
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 29 deletions.
4 changes: 4 additions & 0 deletions RELEASE_NOTES.txt
Expand Up @@ -6,6 +6,10 @@ This file includes a list of high level updates for each milestone release.

Milestone 84

* Add api on GrContext, updateBackendTexture that will upload new data to a
GrBackendTexture.
https://review.skia.org/288555

* GrContext::createBackendTexture functions that initialize the texture no longer
guarantee that all the data has been uploaded and the gpu is done with the texture.
Instead the client can assume the upload work has been submitted to the gpu and they
Expand Down
36 changes: 36 additions & 0 deletions include/gpu/GrContext.h
Expand Up @@ -546,6 +546,42 @@ class SK_API GrContext : public GrRecordingContext {
finishedContext);
}

/**
* If possible, updates a backend texture to be filled to a particular color. The client should
* check the return value to see if the update was successful. The client can pass in a
* finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
* deleted. The client can assume the upload work has been submitted to the gpu. The
* finishedProc will always get called even if we failed to update the GrBackendTexture.
* For the Vulkan backend after a successful update the layout of the created VkImage will be:
* VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
*/
bool updateBackendTexture(const GrBackendTexture&,
const SkColor4f& color,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext);

/**
* If possible, updates a backend texture filled with the provided pixmap data. The client
* should check the return value to see if the update was successful. The client can pass in a
* finishedProc to be notified when the data has been uploaded by the gpu and the texture can be
* deleted. The client can assume the upload work has been submitted to the gpu. The
* finishedProc will always get called even if we failed to create the GrBackendTexture.
* The backend texture must be compatible with the provided pixmap(s). Compatible, in this case,
* means that the backend format is compatible with the base pixmap's colortype.
* If the backend texture is mip mapped, the data for all the mipmap levels must be provided.
* In the mipmapped case all the colortypes of the provided pixmaps must be the same.
* Additionally, all the miplevels must be sized correctly (please see
* SkMipMap::ComputeLevelSize and ComputeLevelCount).
* Note: the pixmap's alphatypes and colorspaces are ignored.
* For the Vulkan backend after a successful update the layout of the created VkImage will be:
* VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
*/
bool updateBackendTexture(const GrBackendTexture&,
const SkPixmap srcData[],
int numLevels,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext);

/**
* Retrieve the GrBackendFormat for a given SkImage::CompressionType. This is
* guaranteed to match the backend format used by the following
Expand Down
52 changes: 52 additions & 0 deletions src/gpu/GrContext.cpp
Expand Up @@ -623,6 +623,58 @@ GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int n
finishedContext, &data);
}

bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture,
const SkColor4f& color,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
if (!this->asDirectContext()) {
finishedProc(finishedContext);
return false;
}

if (this->abandoned()) {
finishedProc(finishedContext);
return false;
}

GrGpu::BackendTextureData data(color);
return fGpu->updateBackendTexture(backendTexture, finishedProc, finishedContext, &data);
}

bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture,
const SkPixmap srcData[],
int numLevels,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
if (!this->asDirectContext()) {
finishedProc(finishedContext);
return false;
}

if (this->abandoned()) {
finishedProc(finishedContext);
return false;
}

if (!srcData || numLevels <= 0) {
finishedProc(finishedContext);
return false;
}

int numExpectedLevels = 1;
if (backendTexture.hasMipMaps()) {
numExpectedLevels = SkMipMap::ComputeLevelCount(backendTexture.width(),
backendTexture.height()) + 1;
}
if (numLevels != numExpectedLevels) {
finishedProc(finishedContext);
return false;
}

GrGpu::BackendTextureData data(srcData);
return fGpu->updateBackendTexture(backendTexture, finishedProc, finishedContext, &data);
}

//////////////////////////////////////////////////////////////////////////////

GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height,
Expand Down
108 changes: 79 additions & 29 deletions tests/BackendAllocationTest.cpp
Expand Up @@ -28,8 +28,7 @@
#include "src/gpu/mtl/GrMtlCppUtil.h"
#endif

static void delete_backend_texture(GrContext* context, const GrBackendTexture& backendTexture,
bool* finishedCreate) {
static void wait_on_backend_work_to_finish(GrContext* context, bool* finishedCreate) {
while (finishedCreate && !(*finishedCreate)) {
context->checkAsyncWorkCompletion();
}
Expand All @@ -39,9 +38,18 @@ static void delete_backend_texture(GrContext* context, const GrBackendTexture& b
// Reset it here so that it can be use to signal a future backend texture's creation
*finishedCreate = false;
}
}

static void delete_backend_texture(GrContext* context, const GrBackendTexture& backendTexture,
bool* finishedCreate) {
wait_on_backend_work_to_finish(context, finishedCreate);
context->deleteBackendTexture(backendTexture);
}

static void mark_signaled(void* context) {
*(bool*)context = true;
}

// Test wrapping of GrBackendObjects in SkSurfaces and SkImages (non-static since used in Mtl test)
void test_wrapping(GrContext* context, skiatest::Reporter* reporter,
std::function<GrBackendTexture (GrContext*,
Expand Down Expand Up @@ -313,16 +321,35 @@ void test_color_init(GrContext* context, skiatest::Reporter* reporter,
return;
}

if (mipMapped == GrMipMapped::kYes) {
SkColor4f expectedColor = get_expected_color(color, skColorType);
SkColor4f expectedColors[6] = { expectedColor, expectedColor, expectedColor,
expectedColor, expectedColor, expectedColor };
check_mipmaps(context, backendTex, skColorType, expectedColors, reporter, "colorinit");
}
auto checkBackendTexture = [&](const SkColor4f& testColor) {
if (mipMapped == GrMipMapped::kYes) {
SkColor4f expectedColor = get_expected_color(testColor, skColorType);
SkColor4f expectedColors[6] = {expectedColor, expectedColor, expectedColor,
expectedColor, expectedColor, expectedColor};
check_mipmaps(context, backendTex, skColorType, expectedColors, reporter, "colorinit");
}

// The last step in this test will dirty the mipmaps so do it last
check_base_readbacks(context, backendTex, skColorType, renderable, testColor, reporter,
"colorinit");
};

checkBackendTexture(color);

// Make sure the initial create work has finished so we can test the update independently.
wait_on_backend_work_to_finish(context, finishedBECreate);

SkColor4f newColor = {color.fB , color.fR, color.fG, color.fA };

// Reupload the new data and make sure everything still works. We test with an SkColorType so
// we may actually swizzle the input during the create path. The update does not do any swizzle
// of the passed in color. So we manually do it here so we get the same expected results.
SkColor4f swizzledColor = context->priv().caps()->getWriteSwizzle(
backendTex.getBackendFormat(), grColorType).applyTo(newColor);
context->updateBackendTexture(backendTex, swizzledColor, mark_signaled, finishedBECreate);

checkBackendTexture(newColor);

// The last step in this test will dirty the mipmaps so do it last
check_base_readbacks(context, backendTex, skColorType, renderable, color,
reporter, "colorinit");
delete_backend_texture(context, backendTex, finishedBECreate);
}

Expand Down Expand Up @@ -461,22 +488,49 @@ static void test_pixmap_init(GrContext* context, skiatest::Reporter* reporter,
return;
}

if (mipMapped == GrMipMapped::kYes) {
SkColor4f expectedColors[6] = {
get_expected_color(colors[0], skColorType),
get_expected_color(colors[1], skColorType),
get_expected_color(colors[2], skColorType),
get_expected_color(colors[3], skColorType),
get_expected_color(colors[4], skColorType),
get_expected_color(colors[5], skColorType),
};

check_mipmaps(context, backendTex, skColorType, expectedColors, reporter, "pixmap");
auto checkBackendTexture = [&](SkColor4f colors[6]) {
if (mipMapped == GrMipMapped::kYes) {
SkColor4f expectedColors[6] = {
get_expected_color(colors[0], skColorType),
get_expected_color(colors[1], skColorType),
get_expected_color(colors[2], skColorType),
get_expected_color(colors[3], skColorType),
get_expected_color(colors[4], skColorType),
get_expected_color(colors[5], skColorType),
};

check_mipmaps(context, backendTex, skColorType, expectedColors, reporter, "pixmap");
}

// The last step in this test will dirty the mipmaps so do it last
check_base_readbacks(context, backendTex, skColorType, renderable, colors[0], reporter,
"pixmap");
};

checkBackendTexture(colors);

// Make sure the initial create work has finished so we can test the update independently.
wait_on_backend_work_to_finish(context, finishedBECreate);

SkColor4f colorsNew[6] = {
{1.0f, 1.0f, 0.0f, 0.2f}, // Y
{1.0f, 0.0f, 0.0f, 1.0f}, // R
{0.0f, 1.0f, 0.0f, 0.9f}, // G
{0.0f, 0.0f, 1.0f, 0.7f}, // B
{0.0f, 1.0f, 1.0f, 0.5f}, // C
{1.0f, 0.0f, 1.0f, 0.3f}, // M
};
make_pixmaps(skColorType, mipMapped, colorsNew, pixmapMem);
for (int i = 0; i < numMipLevels; ++i) {
pixmaps[i].reset(pixmapMem[i].info(), pixmapMem[i].addr(), pixmapMem[i].rowBytes());
}

// The last step in this test will dirty the mipmaps so do it last
check_base_readbacks(context, backendTex, skColorType, renderable, colors[0],
reporter, "pixmap");
// Upload new data and make sure everything still works
context->updateBackendTexture(backendTex, pixmaps, numMipLevels, mark_signaled,
finishedBECreate);

checkBackendTexture(colorsNew);

delete_backend_texture(context, backendTex, finishedBECreate);
}

Expand Down Expand Up @@ -509,10 +563,6 @@ void check_vk_layout(const GrBackendTexture& backendTex, VkLayout layout) {
#endif
}

static void mark_signaled(void* context) {
*(bool*)context = true;
}

///////////////////////////////////////////////////////////////////////////////
// This test is a bit different from the others in this file. It is mainly checking that, for any
// SkSurface we can create in Ganesh, we can also create a backend texture that is compatible with
Expand Down

0 comments on commit ac09f7c

Please sign in to comment.