Commit d8809aa6 authored by Vikas Soni's avatar Vikas Soni Committed by Commit Bot

SurfaceControl: Use only valid region of pixels to calculate src rect.

SurfaceControl was currently using AHardwareBuffer dimensions as a valid
region of pixels to calculate src rect. This do not work always since
actual region of valid pixels could be smaller than the buffer dimensions.
Hence use valid region of pixel instead of buffer dimensions.

Bug: 1027766
Change-Id: Ic289712b71b22be2fc645c771ddcb297b1c6687c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1929632Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Commit-Queue: vikas soni <vikassoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#719462}
parent e6e1e1b5
...@@ -304,6 +304,27 @@ ImageReaderGLOwner::GetAHardwareBuffer() { ...@@ -304,6 +304,27 @@ ImageReaderGLOwner::GetAHardwareBuffer() {
current_image_ref_->GetReadyFence()); current_image_ref_->GetReadyFence());
} }
gfx::Rect ImageReaderGLOwner::GetCropRect() {
if (!current_image_ref_)
return gfx::Rect();
// Note that to query the crop rectangle, we don't need to wait for the
// AImage to be ready by checking the associated image ready fence.
AImageCropRect crop_rect;
media_status_t return_code =
loader_.AImage_getCropRect(current_image_ref_->image(), &crop_rect);
if (return_code != AMEDIA_OK) {
DLOG(ERROR) << "Error querying crop rectangle from the image : "
<< return_code;
return gfx::Rect();
}
DCHECK_GE(crop_rect.right, crop_rect.left);
DCHECK_GE(crop_rect.bottom, crop_rect.top);
return gfx::Rect(crop_rect.left, crop_rect.top,
crop_rect.right - crop_rect.left,
crop_rect.bottom - crop_rect.top);
}
void ImageReaderGLOwner::RegisterRefOnImage(AImage* image) { void ImageReaderGLOwner::RegisterRefOnImage(AImage* image) {
DCHECK(image_reader_); DCHECK(image_reader_);
...@@ -351,22 +372,12 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) { ...@@ -351,22 +372,12 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) {
0, 0, 1, 0, 0, 1, 0, 1}; 0, 0, 1, 0, 0, 1, 0, 1};
memcpy(mtx, kYInvertedIdentity, sizeof(kYInvertedIdentity)); memcpy(mtx, kYInvertedIdentity, sizeof(kYInvertedIdentity));
// Compute the transform matrix only if we have an image available.
if (!current_image_ref_)
return;
// Get the crop rectangle associated with this image. The crop rectangle // Get the crop rectangle associated with this image. The crop rectangle
// specifies the region of valid pixels in the image. // specifies the region of valid pixels in the image.
// Note that to query the crop rectangle, we don't need to wait for the gfx::Rect crop_rect = GetCropRect();
// AImage to be ready by checking the associated image ready fence. if (crop_rect.IsEmpty())
AImageCropRect crop_rect;
media_status_t return_code =
loader_.AImage_getCropRect(current_image_ref_->image(), &crop_rect);
if (return_code != AMEDIA_OK) {
DLOG(ERROR) << "Error querying crop rectangle from the image : "
<< return_code;
return; return;
}
// Get the AHardwareBuffer to query its dimensions. // Get the AHardwareBuffer to query its dimensions.
AHardwareBuffer* buffer = nullptr; AHardwareBuffer* buffer = nullptr;
...@@ -411,11 +422,10 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) { ...@@ -411,11 +422,10 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) {
shrink_amount = 1.0; shrink_amount = 1.0;
} }
int32_t crop_rect_width = (crop_rect.right - crop_rect.left); int32_t crop_rect_width = crop_rect.width();
int32_t crop_rect_height = (crop_rect.bottom - crop_rect.top); int32_t crop_rect_height = crop_rect.height();
DCHECK_GE(crop_rect_width, 0); int32_t crop_rect_left = crop_rect.x();
DCHECK_GE(crop_rect_height, 0); int32_t crop_rect_bottom = crop_rect.y() + crop_rect_height;
int32_t buffer_width = desc.width; int32_t buffer_width = desc.width;
int32_t buffer_height = desc.height; int32_t buffer_height = desc.height;
DCHECK_GT(buffer_width, 0); DCHECK_GT(buffer_width, 0);
...@@ -423,12 +433,12 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) { ...@@ -423,12 +433,12 @@ void ImageReaderGLOwner::GetTransformMatrix(float mtx[]) {
// Only shrink the dimensions that are not the size of the buffer. // Only shrink the dimensions that are not the size of the buffer.
if (crop_rect_width < buffer_width) { if (crop_rect_width < buffer_width) {
tx = (float(crop_rect.left) + shrink_amount) / buffer_width; tx = (float(crop_rect_left) + shrink_amount) / buffer_width;
sx = (float(crop_rect_width) - (2.0f * shrink_amount)) / buffer_width; sx = (float(crop_rect_width) - (2.0f * shrink_amount)) / buffer_width;
} }
if (crop_rect_height < buffer_height) { if (crop_rect_height < buffer_height) {
ty = (float(buffer_height - crop_rect.bottom) + shrink_amount) / ty = (float(buffer_height - crop_rect_bottom) + shrink_amount) /
buffer_height; buffer_height;
sy = (float(crop_rect_height) - (2.0f * shrink_amount)) / buffer_height; sy = (float(crop_rect_height) - (2.0f * shrink_amount)) / buffer_height;
} }
......
...@@ -41,6 +41,7 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner { ...@@ -41,6 +41,7 @@ class GPU_GLES2_EXPORT ImageReaderGLOwner : public TextureOwner {
void ReleaseBackBuffers() override; void ReleaseBackBuffers() override;
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() override; GetAHardwareBuffer() override;
gfx::Rect GetCropRect() override;
const AImageReader* image_reader_for_testing() const { return image_reader_; } const AImageReader* image_reader_for_testing() const { return image_reader_; }
int32_t max_images_for_testing() const { return max_images_; } int32_t max_images_for_testing() const { return max_images_; }
......
...@@ -44,9 +44,15 @@ class MockTextureOwner : public TextureOwner { ...@@ -44,9 +44,15 @@ class MockTextureOwner : public TextureOwner {
return nullptr; return nullptr;
} }
gfx::Rect GetCropRect() override {
++get_crop_rect_count;
return gfx::Rect();
}
gl::GLContext* fake_context; gl::GLContext* fake_context;
gl::GLSurface* fake_surface; gl::GLSurface* fake_surface;
int get_a_hardware_buffer_count = 0; int get_a_hardware_buffer_count = 0;
int get_crop_rect_count = 0;
bool expect_update_tex_image; bool expect_update_tex_image;
protected: protected:
......
...@@ -101,4 +101,9 @@ SurfaceTextureGLOwner::GetAHardwareBuffer() { ...@@ -101,4 +101,9 @@ SurfaceTextureGLOwner::GetAHardwareBuffer() {
return nullptr; return nullptr;
} }
gfx::Rect SurfaceTextureGLOwner::GetCropRect() {
NOTREACHED() << "Don't use GetCropRect with SurfaceTextureGLOwner";
return gfx::Rect();
}
} // namespace gpu } // namespace gpu
...@@ -37,6 +37,7 @@ class GPU_EXPORT SurfaceTextureGLOwner : public TextureOwner { ...@@ -37,6 +37,7 @@ class GPU_EXPORT SurfaceTextureGLOwner : public TextureOwner {
void ReleaseBackBuffers() override; void ReleaseBackBuffers() override;
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() override; GetAHardwareBuffer() override;
gfx::Rect GetCropRect() override;
protected: protected:
void OnTextureDestroyed(gles2::AbstractTexture*) override; void OnTextureDestroyed(gles2::AbstractTexture*) override;
......
...@@ -92,6 +92,10 @@ class GPU_GLES2_EXPORT TextureOwner ...@@ -92,6 +92,10 @@ class GPU_GLES2_EXPORT TextureOwner
virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() = 0; GetAHardwareBuffer() = 0;
// Provides the crop rectangle associated with the most recent image. The
// crop rectangle specifies the region of valid pixels in the image.
virtual gfx::Rect GetCropRect() = 0;
// Set the callback function to run when a new frame is available. // Set the callback function to run when a new frame is available.
// |frame_available_cb| is thread safe and can be called on any thread. This // |frame_available_cb| is thread safe and can be called on any thread. This
// method should be called only once, i.e., once a callback is provided, it // method should be called only once, i.e., once a callback is provided, it
......
...@@ -355,6 +355,12 @@ CodecImage::GetAHardwareBuffer() { ...@@ -355,6 +355,12 @@ CodecImage::GetAHardwareBuffer() {
return codec_buffer_wait_coordinator_->texture_owner()->GetAHardwareBuffer(); return codec_buffer_wait_coordinator_->texture_owner()->GetAHardwareBuffer();
} }
gfx::Rect CodecImage::GetCropRect() {
if (!codec_buffer_wait_coordinator_)
return gfx::Rect();
return codec_buffer_wait_coordinator_->texture_owner()->GetCropRect();
}
bool CodecImage::HasMutableState() const { bool CodecImage::HasMutableState() const {
return false; return false;
} }
......
...@@ -90,6 +90,7 @@ class MEDIA_GPU_EXPORT CodecImage ...@@ -90,6 +90,7 @@ class MEDIA_GPU_EXPORT CodecImage
const std::string& dump_name) override; const std::string& dump_name) override;
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer() override; GetAHardwareBuffer() override;
gfx::Rect GetCropRect() override;
// gpu::gles2::GLStreamTextureMatrix implementation // gpu::gles2::GLStreamTextureMatrix implementation
void GetTextureMatrix(float xform[16]) override; void GetTextureMatrix(float xform[16]) override;
// Currently this API is implemented by the NotifyOverlayPromotion, since this // Currently this API is implemented by the NotifyOverlayPromotion, since this
......
...@@ -414,4 +414,13 @@ TEST_F(CodecImageTest, GetAHardwareBufferAfterRelease) { ...@@ -414,4 +414,13 @@ TEST_F(CodecImageTest, GetAHardwareBufferAfterRelease) {
EXPECT_FALSE(i->GetAHardwareBuffer()); EXPECT_FALSE(i->GetAHardwareBuffer());
} }
TEST_F(CodecImageTest, GetCropRect) {
auto i = NewImage(kTextureOwner);
EXPECT_EQ(
codec_buffer_wait_coordinator_->texture_owner()->get_crop_rect_count, 0);
i->GetCropRect();
EXPECT_EQ(
codec_buffer_wait_coordinator_->texture_owner()->get_crop_rect_count, 1);
}
} // namespace media } // namespace media
...@@ -34,6 +34,10 @@ std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> ...@@ -34,6 +34,10 @@ std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GLImage::GetAHardwareBuffer() { GLImage::GetAHardwareBuffer() {
return nullptr; return nullptr;
} }
gfx::Rect GLImage::GetCropRect() {
return gfx::Rect();
}
#endif #endif
bool GLImage::HasMutableState() const { bool GLImage::HasMutableState() const {
......
...@@ -139,6 +139,10 @@ class GL_EXPORT GLImage : public base::RefCounted<GLImage> { ...@@ -139,6 +139,10 @@ class GL_EXPORT GLImage : public base::RefCounted<GLImage> {
// returned. // returned.
virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync> virtual std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
GetAHardwareBuffer(); GetAHardwareBuffer();
// Provides the crop rectangle associated with the image. The crop rectangle
// specifies the region of valid pixels in the image.
virtual gfx::Rect GetCropRect();
#endif #endif
// An identifier for subclasses. Necessary for safe downcasting. // An identifier for subclasses. Necessary for safe downcasting.
......
...@@ -329,12 +329,27 @@ bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane( ...@@ -329,12 +329,27 @@ bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane(
if (hardware_buffer) { if (hardware_buffer) {
gfx::Rect dst = bounds_rect; gfx::Rect dst = bounds_rect;
// Get the crop rectangle from the image which is the actual region of valid
// pixels. This region could be smaller than the buffer dimensions. Hence
// scale the |crop_rect| according to the valid pixel area rather than
// buffer dimensions. crbug.com/1027766 for more details.
gfx::Rect valid_pixel_rect = image->GetCropRect();
gfx::Size buffer_size = GetBufferSize(hardware_buffer); gfx::Size buffer_size = GetBufferSize(hardware_buffer);
gfx::RectF scaled_rect =
gfx::RectF(crop_rect.x() * buffer_size.width(), // If the image doesn't provide a |valid_pixel_rect|, assume the entire
crop_rect.y() * buffer_size.height(), // buffer is valid.
crop_rect.width() * buffer_size.width(), if (valid_pixel_rect.IsEmpty()) {
crop_rect.height() * buffer_size.height()); valid_pixel_rect.set_size(buffer_size);
} else {
// Clamp the |valid_pixel_rect| to the buffer dimensions to make sure for
// some reason it does not overflows.
valid_pixel_rect.Intersect(gfx::Rect(buffer_size));
}
gfx::RectF scaled_rect = gfx::RectF(
crop_rect.x() * valid_pixel_rect.width() + valid_pixel_rect.x(),
crop_rect.y() * valid_pixel_rect.height() + valid_pixel_rect.y(),
crop_rect.width() * valid_pixel_rect.width(),
crop_rect.height() * valid_pixel_rect.height());
gfx::Rect src = gfx::ToEnclosedRect(scaled_rect); gfx::Rect src = gfx::ToEnclosedRect(scaled_rect);
if (uninitialized || surface_state.src != src || surface_state.dst != dst || if (uninitialized || surface_state.src != src || surface_state.dst != dst ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment