Skip to content

Commit

Permalink
Add YUV to RGB Conversion to RasterImplementation
Browse files Browse the repository at this point in the history
RasterInterface is still missing a few APIs that are necessary for OOP
rasterization for Canvas2D. This CL adds support for YUV to RGB
conversion using Skia in GPU process.

Bug: 1058992
Change-Id: Ia47feaa1dddcea6057b6ceb57cf17d4edd12c2e2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2163811
Commit-Queue: Nathan Zabriskie <nazabris@microsoft.com>
Reviewed-by: Khushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#763140}
  • Loading branch information
NathanZabriskie authored and Commit Bot committed Apr 28, 2020
1 parent f76bc10 commit 366b893
Show file tree
Hide file tree
Showing 14 changed files with 567 additions and 44 deletions.
161 changes: 140 additions & 21 deletions cc/paint/oop_pixeltest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "gpu/ipc/gl_in_process_context.h"
#include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkFontLCDConfig.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/core/SkSurface.h"
Expand Down Expand Up @@ -256,6 +257,20 @@ class OopPixelTest : public testing::Test,
return bitmap;
}

gpu::Mailbox CreateMailboxSharedImage(gpu::raster::RasterInterface* ri,
gpu::SharedImageInterface* sii,
const RasterOptions& options,
viz::ResourceFormat image_format) {
uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER |
gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
gpu::Mailbox mailbox = sii->CreateSharedImage(
image_format, options.resource_size, options.color_space, flags);
EXPECT_TRUE(mailbox.Verify());
ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());

return mailbox;
}

SkBitmap RasterExpectedBitmap(
scoped_refptr<DisplayItemList> display_item_list,
const gfx::Size& playback_size) {
Expand Down Expand Up @@ -1619,32 +1634,23 @@ TEST_F(OopPixelTest, DrawTextBlobPersistentShaderCache) {
}

TEST_F(OopPixelTest, WritePixels) {
gfx::Rect rect(10, 10);
RasterOptions options(rect.size());
auto* raster_implementation = raster_context_provider_->RasterInterface();
gfx::Size dest_size(10, 10);
RasterOptions options(dest_size);
auto* ri = raster_context_provider_->RasterInterface();
auto* sii = raster_context_provider_->SharedImageInterface();
uint32_t flags = gpu::SHARED_IMAGE_USAGE_RASTER |
gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
gpu::Mailbox dest_mailbox = sii->CreateSharedImage(
viz::ResourceFormat::RGBA_8888, gfx::Size(rect.width(), rect.height()),
options.color_space, flags);
EXPECT_TRUE(dest_mailbox.Verify());
raster_implementation->WaitSyncTokenCHROMIUM(
sii->GenUnverifiedSyncToken().GetConstData());

std::vector<SkPMColor> expected_pixels(rect.width() * rect.height(),
gpu::Mailbox dest_mailbox = CreateMailboxSharedImage(
ri, sii, options, viz::ResourceFormat::RGBA_8888);
std::vector<SkPMColor> expected_pixels(dest_size.width() * dest_size.height(),
SkPreMultiplyARGB(255, 0, 0, 255));
SkBitmap expected;
expected.installPixels(
SkImageInfo::MakeN32Premul(rect.width(), rect.height()),
expected_pixels.data(), rect.width() * sizeof(SkColor));
SkImageInfo::MakeN32Premul(dest_size.width(), dest_size.height()),
expected_pixels.data(), dest_size.width() * sizeof(SkColor));

raster_implementation->WritePixels(dest_mailbox, 0, 0, 0,
expected.info().minRowBytes(),
expected.info(), expected.getPixels());
raster_implementation->OrderingBarrierCHROMIUM();
EXPECT_EQ(raster_implementation->GetError(),
static_cast<unsigned>(GL_NO_ERROR));
ri->WritePixels(dest_mailbox, 0, 0, 0, expected.info().minRowBytes(),
expected.info(), expected.getPixels());
ri->OrderingBarrierCHROMIUM();
EXPECT_EQ(ri->GetError(), static_cast<unsigned>(GL_NO_ERROR));

gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
SkBitmap actual = ReadbackMailbox(gl, dest_mailbox, options);
Expand All @@ -1654,6 +1660,119 @@ TEST_F(OopPixelTest, WritePixels) {
ExpectEquals(actual, expected);
}

namespace {
void UploadPixels(gpu::gles2::GLES2Interface* gl,
const gpu::Mailbox& mailbox,
const gfx::Size& size,
GLenum format,
GLenum type,
const void* data) {
GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
gl->BindTexture(GL_TEXTURE_2D, texture);
gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), format,
type, data);
gl->BindTexture(GL_TEXTURE_2D, 0);
gl->DeleteTextures(1, &texture);
}
} // namespace

TEST_F(OopPixelTest, ConvertYUVToRGB) {
RasterOptions options(gfx::Size(16, 16));
RasterOptions uv_options(gfx::Size(options.resource_size.width() / 2,
options.resource_size.height() / 2));
auto* ri = raster_context_provider_->RasterInterface();
auto* sii = raster_context_provider_->SharedImageInterface();
gpu::Mailbox dest_mailbox = CreateMailboxSharedImage(
ri, sii, options, viz::ResourceFormat::RGBA_8888);
gpu::Mailbox y_mailbox = CreateMailboxSharedImage(
ri, sii, options, viz::ResourceFormat::LUMINANCE_8);
gpu::Mailbox u_mailbox = CreateMailboxSharedImage(
ri, sii, uv_options, viz::ResourceFormat::LUMINANCE_8);
gpu::Mailbox v_mailbox = CreateMailboxSharedImage(
ri, sii, uv_options, viz::ResourceFormat::LUMINANCE_8);

size_t y_pixels_size = options.resource_size.GetArea();
size_t uv_pixels_size = uv_options.resource_size.GetArea();
auto y_pix = std::make_unique<uint8_t[]>(y_pixels_size);
auto u_pix = std::make_unique<uint8_t[]>(uv_pixels_size);
auto v_pix = std::make_unique<uint8_t[]>(uv_pixels_size);

// Create a blue image
memset(y_pix.get(), 0x1d, y_pixels_size);
memset(u_pix.get(), 0xff, uv_pixels_size);
memset(v_pix.get(), 0x6b, uv_pixels_size);

// Upload initial yuv image data
gpu::gles2::GLES2Interface* gl = gles2_context_provider_->ContextGL();
UploadPixels(gl, y_mailbox, options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, y_pix.get());
UploadPixels(gl, u_mailbox, uv_options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, u_pix.get());
UploadPixels(gl, v_mailbox, uv_options.resource_size, GL_LUMINANCE,
GL_UNSIGNED_BYTE, v_pix.get());
gl->OrderingBarrierCHROMIUM();

ri->ConvertYUVMailboxesToRGB(dest_mailbox, kJPEG_SkYUVColorSpace, y_mailbox,
u_mailbox, v_mailbox);
ri->OrderingBarrierCHROMIUM();
SkBitmap actual_bitmap = ReadbackMailbox(gl, dest_mailbox, options);

// Create the expected result using SkImage::MakeFromYUVTextures
GrGLTextureInfo backend_info[3];
backend_info[0] = {
GL_TEXTURE_2D,
gl->CreateAndTexStorage2DSharedImageCHROMIUM(y_mailbox.name),
GL_LUMINANCE8_EXT};
backend_info[1] = {
GL_TEXTURE_2D,
gl->CreateAndTexStorage2DSharedImageCHROMIUM(u_mailbox.name),
GL_LUMINANCE8_EXT};
backend_info[2] = {
GL_TEXTURE_2D,
gl->CreateAndTexStorage2DSharedImageCHROMIUM(v_mailbox.name),
GL_LUMINANCE8_EXT};

GrBackendTexture backend_textures[3];
backend_textures[0] = GrBackendTexture(options.resource_size.width(),
options.resource_size.height(),
GrMipMapped::kNo, backend_info[0]);
backend_textures[1] = GrBackendTexture(uv_options.resource_size.width(),
uv_options.resource_size.height(),
GrMipMapped::kNo, backend_info[1]);
backend_textures[2] = GrBackendTexture(uv_options.resource_size.width(),
uv_options.resource_size.height(),
GrMipMapped::kNo, backend_info[2]);

SkYUVAIndex yuva_indices[4];
yuva_indices[SkYUVAIndex::kY_Index] = {0, SkColorChannel::kR};
yuva_indices[SkYUVAIndex::kU_Index] = {1, SkColorChannel::kR};
yuva_indices[SkYUVAIndex::kV_Index] = {2, SkColorChannel::kR};
yuva_indices[SkYUVAIndex::kA_Index] = {-1, SkColorChannel::kA};

auto expected_image = SkImage::MakeFromYUVATextures(
gles2_context_provider_->GrContext(), kJPEG_SkYUVColorSpace,
backend_textures, yuva_indices,
{options.resource_size.width(), options.resource_size.height()},
kTopLeft_GrSurfaceOrigin, nullptr);

SkBitmap expected_bitmap;
expected_bitmap.allocN32Pixels(options.resource_size.width(),
options.resource_size.height());
expected_image->readPixels(expected_bitmap.pixmap(), 0, 0);
ExpectEquals(actual_bitmap, expected_bitmap);

for (auto& backend : backend_info) {
gl->DeleteTextures(1, &backend.fID);
}

gpu::SyncToken sync_token;
gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
sii->DestroySharedImage(sync_token, dest_mailbox);
sii->DestroySharedImage(sync_token, y_mailbox);
sii->DestroySharedImage(sync_token, u_mailbox);
sii->DestroySharedImage(sync_token, v_mailbox);
}

class OopPathPixelTest : public OopPixelTest,
public ::testing::WithParamInterface<bool> {
public:
Expand Down
8 changes: 8 additions & 0 deletions gpu/command_buffer/build_raster_cmd_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@
'unit_test': False,
'trace_level': 2,
},
'ConvertYUVMailboxesToRGBINTERNAL': {
'decoder_func': 'DoConvertYUVMailboxesToRGBINTERNAL',
'internal': True,
'type': 'PUT',
'count': 64, #GL_MAILBOX_SIZE_CHROMIUM x4
'unit_test': False,
'trace_level': 2,
},
'Finish': {
'impl_func': False,
'client_test': False,
Expand Down
12 changes: 12 additions & 0 deletions gpu/command_buffer/client/raster_cmd_helper_autogen.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,18 @@ void WritePixelsINTERNALImmediate(GLint x_offset,
}
}

void ConvertYUVMailboxesToRGBINTERNALImmediate(GLenum planes_yuv_color_space,
const GLbyte* mailboxes) {
const uint32_t size =
raster::cmds::ConvertYUVMailboxesToRGBINTERNALImmediate::ComputeSize();
raster::cmds::ConvertYUVMailboxesToRGBINTERNALImmediate* c =
GetImmediateCmdSpaceTotalSize<
raster::cmds::ConvertYUVMailboxesToRGBINTERNALImmediate>(size);
if (c) {
c->Init(planes_yuv_color_space, mailboxes);
}
}

void TraceBeginCHROMIUM(GLuint category_bucket_id, GLuint name_bucket_id) {
raster::cmds::TraceBeginCHROMIUM* c =
GetCmdSpace<raster::cmds::TraceBeginCHROMIUM>();
Expand Down
77 changes: 59 additions & 18 deletions gpu/command_buffer/client/raster_implementation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,47 @@ namespace {

const uint32_t kMaxTransferCacheEntrySizeForTransferBuffer = 1024;

class ScopedSharedMemoryPtr {
public:
ScopedSharedMemoryPtr(size_t size,
TransferBufferInterface* transfer_buffer,
MappedMemoryManager* mapped_memory,
RasterCmdHelper* helper) {
// Prefer transfer buffer but fall back to MappedMemory if there's not
// enough free space.
if (transfer_buffer->GetFreeSize() < size) {
scoped_mapped_ptr_.emplace(size, helper, mapped_memory);
} else {
scoped_transfer_ptr_.emplace(size, helper, transfer_buffer);
}
}
~ScopedSharedMemoryPtr() = default;

GLuint size() {
return scoped_transfer_ptr_ ? scoped_transfer_ptr_->size()
: scoped_mapped_ptr_->size();
}

GLint shm_id() {
return scoped_transfer_ptr_ ? scoped_transfer_ptr_->shm_id()
: scoped_mapped_ptr_->shm_id();
}

GLuint offset() {
return scoped_transfer_ptr_ ? scoped_transfer_ptr_->offset()
: scoped_mapped_ptr_->offset();
}

void* address() {
return scoped_transfer_ptr_ ? scoped_transfer_ptr_->address()
: scoped_mapped_ptr_->address();
}

private:
base::Optional<ScopedMappedMemoryPtr> scoped_mapped_ptr_;
base::Optional<ScopedTransferBufferPtr> scoped_transfer_ptr_;
};

} // namespace

// Helper to copy data to the GPU service over the transfer cache.
Expand Down Expand Up @@ -1090,24 +1131,11 @@ void RasterImplementation::WritePixels(const gpu::Mailbox& dest_mailbox,
GLuint total_size =
pixels_offset + base::bits::Align(src_size, sizeof(uint64_t));

GLint shm_id;
GLuint shm_offset;
void* address;
base::Optional<ScopedMappedMemoryPtr> mapped_ptr;
base::Optional<ScopedTransferBufferPtr> transfer_ptr;
// Prefer transfer buffer but fall back to MappedMemory if there's not enough
// free space.
if (transfer_buffer_->GetFreeSize() < total_size) {
mapped_ptr.emplace(total_size, helper(), mapped_memory_.get());
shm_id = mapped_ptr->shm_id();
shm_offset = mapped_ptr->offset();
address = mapped_ptr->address();
} else {
transfer_ptr.emplace(total_size, helper(), transfer_buffer_);
shm_id = transfer_ptr->shm_id();
shm_offset = transfer_ptr->offset();
address = transfer_ptr->address();
}
ScopedSharedMemoryPtr scoped_shared_memory(total_size, transfer_buffer_,
mapped_memory_.get(), helper());
GLint shm_id = scoped_shared_memory.shm_id();
GLuint shm_offset = scoped_shared_memory.offset();
void* address = scoped_shared_memory.address();

if (src_info.colorSpace()) {
size_t bytes_written = src_info.colorSpace()->writeToMemory(address);
Expand All @@ -1121,6 +1149,19 @@ void RasterImplementation::WritePixels(const gpu::Mailbox& dest_mailbox,
pixels_offset, dest_mailbox.name);
}

void RasterImplementation::ConvertYUVMailboxesToRGB(
const gpu::Mailbox& dest_mailbox,
SkYUVColorSpace planes_yuv_color_space,
const gpu::Mailbox& y_plane_mailbox,
const gpu::Mailbox& u_plane_mailbox,
const gpu::Mailbox& v_plane_mailbox) {
constexpr size_t NUM_MAILBOXES = 4;
gpu::Mailbox mailboxes[NUM_MAILBOXES] = {y_plane_mailbox, u_plane_mailbox,
v_plane_mailbox, dest_mailbox};
helper_->ConvertYUVMailboxesToRGBINTERNALImmediate(
planes_yuv_color_space, reinterpret_cast<GLbyte*>(mailboxes));
}

void RasterImplementation::BeginRasterCHROMIUM(
GLuint sk_color,
GLuint msaa_sample_count,
Expand Down
6 changes: 6 additions & 0 deletions gpu/command_buffer/client/raster_implementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ class RASTER_EXPORT RasterImplementation : public RasterInterface,
const SkImageInfo& src_info,
const void* src_pixels) override;

void ConvertYUVMailboxesToRGB(const gpu::Mailbox& dest_mailbox,
SkYUVColorSpace planes_yuv_color_space,
const gpu::Mailbox& y_plane_mailbox,
const gpu::Mailbox& u_plane_mailbox,
const gpu::Mailbox& v_plane_mailbox) override;

void BeginRasterCHROMIUM(GLuint sk_color,
GLuint msaa_sample_count,
GLboolean can_use_lcd_text,
Expand Down
9 changes: 9 additions & 0 deletions gpu/command_buffer/client/raster_implementation_gles.cc
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ void RasterImplementationGLES::WritePixels(const gpu::Mailbox& dest_mailbox,
DeleteGpuRasterTexture(texture_id);
}

void RasterImplementationGLES::ConvertYUVMailboxesToRGB(
const gpu::Mailbox& dest_mailbox,
SkYUVColorSpace planes_yuv_color_space,
const gpu::Mailbox& y_plane_mailbox,
const gpu::Mailbox& u_plane_mailbox,
const gpu::Mailbox& v_plane_mailbox) {
NOTREACHED();
}

void RasterImplementationGLES::BeginRasterCHROMIUM(
GLuint sk_color,
GLuint msaa_sample_count,
Expand Down
6 changes: 6 additions & 0 deletions gpu/command_buffer/client/raster_implementation_gles.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class RASTER_EXPORT RasterImplementationGLES : public RasterInterface {
const SkImageInfo& src_info,
const void* src_pixels) override;

void ConvertYUVMailboxesToRGB(const gpu::Mailbox& dest_mailbox,
SkYUVColorSpace planes_yuv_color_space,
const gpu::Mailbox& y_plane_mailbox,
const gpu::Mailbox& u_plane_mailbox,
const gpu::Mailbox& v_plane_mailbox) override;

// OOP-Raster
void BeginRasterCHROMIUM(GLuint sk_color,
GLuint msaa_sample_count,
Expand Down
10 changes: 8 additions & 2 deletions gpu/command_buffer/client/raster_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
#include "components/viz/common/resources/resource_format.h"
#include "gpu/command_buffer/client/interface_base.h"
#include "gpu/command_buffer/common/sync_token.h"

struct SkImageInfo;
#include "third_party/skia/include/core/SkImageInfo.h"

namespace cc {
class DisplayItemList;
Expand Down Expand Up @@ -65,6 +64,13 @@ class RasterInterface : public InterfaceBase {
const SkImageInfo& src_info,
const void* src_pixels) = 0;

virtual void ConvertYUVMailboxesToRGB(
const gpu::Mailbox& dest_mailbox,
SkYUVColorSpace planes_yuv_color_space,
const gpu::Mailbox& y_plane_mailbox,
const gpu::Mailbox& u_plane_mailbox,
const gpu::Mailbox& v_plane_mailbox) = 0;

// OOP-Raster
virtual void BeginRasterCHROMIUM(GLuint sk_color,
GLuint msaa_sample_count,
Expand Down
Loading

0 comments on commit 366b893

Please sign in to comment.