Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1153)

Side by Side Diff: media/renderers/skcanvas_video_renderer.cc

Issue 2791813003: Fix broken draw/upload paths from videos to 2D canvas and WebGL. (Closed)
Patch Set: Disable GPU-GPU copies to floating-point textures on Android. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/renderers/skcanvas_video_renderer.h" 5 #include "media/renderers/skcanvas_video_renderer.h"
6 6
7 #include <GLES3/gl3.h> 7 #include <GLES3/gl3.h>
8 #include <limits> 8 #include <limits>
9 9
10 #include "base/macros.h" 10 #include "base/macros.h"
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 handles, yuvSizes, 153 handles, yuvSizes,
154 kTopLeft_GrSurfaceOrigin); 154 kTopLeft_GrSurfaceOrigin);
155 } 155 }
156 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format()); 156 for (size_t i = 0; i < media::VideoFrame::NumPlanes(video_frame->format());
157 ++i) { 157 ++i) {
158 gl->DeleteTextures(1, &source_textures[i].fID); 158 gl->DeleteTextures(1, &source_textures[i].fID);
159 } 159 }
160 return img; 160 return img;
161 } 161 }
162 162
163 bool VideoTextureNeedsClipping(const VideoFrame* video_frame) {
164 // There are multiple reasons that the size of the video frame's
165 // visible rectangle may differ from the coded size, including the
166 // encoder rounding up to the size of a macroblock, or use of
167 // non-square pixels.
168 //
169 // Some callers of these APIs (HTMLVideoElement and the 2D canvas
170 // context) already clip to the video frame's visible rectangle.
171 // WebGL on the other hand assumes that only the valid pixels are
172 // contained in the destination texture. This helper function
173 // determines whether this slower path is needed.
174 return video_frame->visible_rect().size() != video_frame->coded_size();
175 }
176
163 // Creates a SkImage from a |video_frame| backed by native resources. 177 // Creates a SkImage from a |video_frame| backed by native resources.
164 // The SkImage will take ownership of the underlying resource. 178 // The SkImage will take ownership of the underlying resource.
165 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame, 179 sk_sp<SkImage> NewSkImageFromVideoFrameNative(VideoFrame* video_frame,
166 const Context3D& context_3d) { 180 const Context3D& context_3d) {
167 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || 181 DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
168 PIXEL_FORMAT_XRGB == video_frame->format() || 182 PIXEL_FORMAT_XRGB == video_frame->format() ||
169 PIXEL_FORMAT_NV12 == video_frame->format() || 183 PIXEL_FORMAT_NV12 == video_frame->format() ||
170 PIXEL_FORMAT_UYVY == video_frame->format()); 184 PIXEL_FORMAT_UYVY == video_frame->format());
171 185
172 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 186 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
173 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 187 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
174 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 188 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
175 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) 189 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
176 << mailbox_holder.texture_target; 190 << mailbox_holder.texture_target;
177 191
178 gpu::gles2::GLES2Interface* gl = context_3d.gl; 192 gpu::gles2::GLES2Interface* gl = context_3d.gl;
179 unsigned source_texture = 0; 193 unsigned source_texture = 0;
180 if (mailbox_holder.texture_target != GL_TEXTURE_2D) { 194 if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
181 // TODO(dcastagna): At the moment Skia doesn't support targets different 195 // TODO(dcastagna): At the moment Skia doesn't support targets different
182 // than GL_TEXTURE_2D. Avoid this copy once 196 // than GL_TEXTURE_2D. Avoid this copy once
183 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed. 197 // https://code.google.com/p/skia/issues/detail?id=3868 is addressed.
184 gl->GenTextures(1, &source_texture); 198 gl->GenTextures(1, &source_texture);
185 DCHECK(source_texture); 199 DCHECK(source_texture);
186 gl->BindTexture(GL_TEXTURE_2D, source_texture); 200 gl->BindTexture(GL_TEXTURE_2D, source_texture);
187 const gfx::Size& natural_size = video_frame->natural_size();
188 gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, natural_size.width(),
189 natural_size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
190 nullptr);
191 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( 201 SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
192 gl, video_frame, source_texture, true, false); 202 gl, video_frame,
203 SkCanvasVideoRenderer::SingleFrameForVideoElementOrCanvas,
204 source_texture, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, true, false);
193 } else { 205 } else {
194 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 206 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
195 source_texture = gl->CreateAndConsumeTextureCHROMIUM( 207 source_texture = gl->CreateAndConsumeTextureCHROMIUM(
196 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 208 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
197 } 209 }
198 GrBackendTextureDesc desc; 210 GrBackendTextureDesc desc;
199 desc.fFlags = kRenderTarget_GrBackendTextureFlag; 211 desc.fFlags = kRenderTarget_GrBackendTextureFlag;
200 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 212 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
201 desc.fWidth = video_frame->coded_size().width(); 213 desc.fWidth = video_frame->coded_size().width();
202 desc.fHeight = video_frame->coded_size().height(); 214 desc.fHeight = video_frame->coded_size().height();
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after
746 case PIXEL_FORMAT_Y8: 758 case PIXEL_FORMAT_Y8:
747 case PIXEL_FORMAT_UNKNOWN: 759 case PIXEL_FORMAT_UNKNOWN:
748 NOTREACHED() << "Only YUV formats and Y16 are supported."; 760 NOTREACHED() << "Only YUV formats and Y16 are supported.";
749 } 761 }
750 } 762 }
751 763
752 // static 764 // static
753 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( 765 void SkCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
754 gpu::gles2::GLES2Interface* gl, 766 gpu::gles2::GLES2Interface* gl,
755 VideoFrame* video_frame, 767 VideoFrame* video_frame,
768 SingleFrameCopyMode copy_mode,
756 unsigned int texture, 769 unsigned int texture,
770 unsigned int internal_format,
771 unsigned int format,
772 unsigned int type,
757 bool premultiply_alpha, 773 bool premultiply_alpha,
758 bool flip_y) { 774 bool flip_y) {
759 DCHECK(video_frame); 775 DCHECK(video_frame);
760 DCHECK(video_frame->HasTextures()); 776 DCHECK(video_frame->HasTextures());
761 777
762 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); 778 const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0);
763 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || 779 DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
764 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || 780 mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
765 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) 781 mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
766 << mailbox_holder.texture_target; 782 << mailbox_holder.texture_target;
767 783
768 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); 784 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
769 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM( 785 uint32_t source_texture = gl->CreateAndConsumeTextureCHROMIUM(
770 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 786 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
771 787
772 // The video is stored in a unmultiplied format, so premultiply 788 // The video is stored in a unmultiplied format, so premultiply
773 // if necessary. 789 // if necessary.
774 // Application itself needs to take care of setting the right |flip_y| 790 // Application itself needs to take care of setting the right |flip_y|
775 // value down to get the expected result. 791 // value down to get the expected result.
776 // "flip_y == true" means to reverse the video orientation while 792 // "flip_y == true" means to reverse the video orientation while
777 // "flip_y == false" means to keep the intrinsic orientation. 793 // "flip_y == false" means to keep the intrinsic orientation.
778 794
779 // The video's texture might be larger than the natural size because 795 if (copy_mode == SingleFrameForVideoElementOrCanvas ||
780 // the encoder might have had to round up to the size of a macroblock. 796 !VideoTextureNeedsClipping(video_frame)) {
781 // Make sure to only copy the natural size to avoid putting garbage 797 // No need to clip the source video texture.
782 // into the bottom of the destination texture. 798 gl->CopyTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0,
783 const gfx::Size& natural_size = video_frame->natural_size(); 799 internal_format, type, flip_y, premultiply_alpha,
784 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 800 false);
785 0, 0, natural_size.width(), natural_size.height(), 801 } else {
786 flip_y, premultiply_alpha, false); 802 // Must reallocate the destination texture and copy only a sub-portion.
803 gfx::Rect dest_rect = video_frame->visible_rect();
804 #if DCHECK_IS_ON()
805 // The caller should have bound _texture_ to the GL_TEXTURE_2D
806 // binding point already.
807 GLuint current_texture = 0;
808 gl->GetIntegerv(GL_TEXTURE_BINDING_2D,
809 reinterpret_cast<GLint*>(&current_texture));
810 DCHECK_EQ(current_texture, texture);
811 // There should always be enough data in the source texture to
812 // cover this copy.
813 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width());
814 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height());
815 #endif
816 gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format, dest_rect.width(),
817 dest_rect.height(), 0, format, type, nullptr);
818 gl->CopySubTextureCHROMIUM(source_texture, 0, GL_TEXTURE_2D, texture, 0, 0,
819 0, dest_rect.x(), dest_rect.y(),
820 dest_rect.width(), dest_rect.height(), flip_y,
821 premultiply_alpha, false);
822 }
823
787 gl->DeleteTextures(1, &source_texture); 824 gl->DeleteTextures(1, &source_texture);
788 gl->Flush(); 825 gl->Flush();
789 826
790 SyncTokenClientImpl client(gl); 827 SyncTokenClientImpl client(gl);
791 video_frame->UpdateReleaseSyncToken(&client); 828 video_frame->UpdateReleaseSyncToken(&client);
792 } 829 }
793 830
794 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( 831 bool SkCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
795 const Context3D& context_3d, 832 const Context3D& context_3d,
796 gpu::gles2::GLES2Interface* destination_gl, 833 gpu::gles2::GLES2Interface* destination_gl,
797 const scoped_refptr<VideoFrame>& video_frame, 834 const scoped_refptr<VideoFrame>& video_frame,
798 unsigned int texture, 835 unsigned int texture,
836 unsigned int internal_format,
837 unsigned int format,
838 unsigned int type,
799 bool premultiply_alpha, 839 bool premultiply_alpha,
800 bool flip_y) { 840 bool flip_y) {
801 DCHECK(thread_checker_.CalledOnValidThread()); 841 DCHECK(thread_checker_.CalledOnValidThread());
802 DCHECK(video_frame); 842 DCHECK(video_frame);
803 DCHECK(video_frame->HasTextures()); 843 DCHECK(video_frame->HasTextures());
804 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) { 844 if (media::VideoFrame::NumPlanes(video_frame->format()) > 1) {
805 if (!context_3d.gr_context) 845 if (!context_3d.gr_context)
806 return false; 846 return false;
807 if (!UpdateLastImage(video_frame, context_3d)) 847 if (!UpdateLastImage(video_frame, context_3d))
808 return false; 848 return false;
(...skipping 16 matching lines...) Expand all
825 canvas_gl->ShallowFlushCHROMIUM(); 865 canvas_gl->ShallowFlushCHROMIUM();
826 canvas_gl->GenSyncTokenCHROMIUM(fence_sync, 866 canvas_gl->GenSyncTokenCHROMIUM(fence_sync,
827 mailbox_holder.sync_token.GetData()); 867 mailbox_holder.sync_token.GetData());
828 868
829 destination_gl->WaitSyncTokenCHROMIUM( 869 destination_gl->WaitSyncTokenCHROMIUM(
830 mailbox_holder.sync_token.GetConstData()); 870 mailbox_holder.sync_token.GetConstData());
831 uint32_t intermediate_texture = 871 uint32_t intermediate_texture =
832 destination_gl->CreateAndConsumeTextureCHROMIUM( 872 destination_gl->CreateAndConsumeTextureCHROMIUM(
833 mailbox_holder.texture_target, mailbox_holder.mailbox.name); 873 mailbox_holder.texture_target, mailbox_holder.mailbox.name);
834 874
835 // The video's texture might be larger than the natural size because 875 // See whether the source video texture must be clipped.
836 // the encoder might have had to round up to the size of a macroblock. 876 if (VideoTextureNeedsClipping(video_frame.get())) {
837 // Make sure to only copy the natural size to avoid putting garbage 877 // Reallocate destination texture and copy only valid region.
838 // into the bottom of the destination texture. 878 gfx::Rect dest_rect = video_frame->visible_rect();
839 const gfx::Size& natural_size = video_frame->natural_size(); 879 #if DCHECK_IS_ON()
840 destination_gl->CopySubTextureCHROMIUM( 880 // The caller should have bound _texture_ to the GL_TEXTURE_2D
841 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0, 0, 0, 881 // binding point already.
842 natural_size.width(), natural_size.height(), flip_y, premultiply_alpha, 882 GLuint current_texture = 0;
843 false); 883 destination_gl->GetIntegerv(GL_TEXTURE_BINDING_2D,
884 reinterpret_cast<GLint*>(&current_texture));
885 DCHECK_EQ(current_texture, texture);
886 // There should always be enough data in the source texture to
887 // cover this copy.
888 DCHECK_LE(dest_rect.width(), video_frame->coded_size().width());
889 DCHECK_LE(dest_rect.height(), video_frame->coded_size().height());
890 #endif
891 destination_gl->TexImage2D(GL_TEXTURE_2D, 0, internal_format,
892 dest_rect.width(), dest_rect.height(), 0,
893 format, type, nullptr);
894 destination_gl->CopySubTextureCHROMIUM(
895 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, 0, 0,
896 dest_rect.x(), dest_rect.y(), dest_rect.width(), dest_rect.height(),
897 flip_y, premultiply_alpha, false);
898 } else {
899 destination_gl->CopyTextureCHROMIUM(
900 intermediate_texture, 0, GL_TEXTURE_2D, texture, 0, internal_format,
901 type, flip_y, premultiply_alpha, false);
902 }
903
844 destination_gl->DeleteTextures(1, &intermediate_texture); 904 destination_gl->DeleteTextures(1, &intermediate_texture);
845 905
846 // Wait for destination context to consume mailbox before deleting it in 906 // Wait for destination context to consume mailbox before deleting it in
847 // canvas context. 907 // canvas context.
848 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM(); 908 const GLuint64 dest_fence_sync = destination_gl->InsertFenceSyncCHROMIUM();
849 destination_gl->ShallowFlushCHROMIUM(); 909 destination_gl->ShallowFlushCHROMIUM();
850 gpu::SyncToken dest_sync_token; 910 gpu::SyncToken dest_sync_token;
851 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync, 911 destination_gl->GenSyncTokenCHROMIUM(dest_fence_sync,
852 dest_sync_token.GetData()); 912 dest_sync_token.GetData());
853 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData()); 913 canvas_gl->WaitSyncTokenCHROMIUM(dest_sync_token.GetConstData());
854 914
855 SyncTokenClientImpl client(canvas_gl); 915 SyncTokenClientImpl client(canvas_gl);
856 video_frame->UpdateReleaseSyncToken(&client); 916 video_frame->UpdateReleaseSyncToken(&client);
857 } else { 917 } else {
858 CopyVideoFrameSingleTextureToGLTexture(destination_gl, video_frame.get(), 918 CopyVideoFrameSingleTextureToGLTexture(
859 texture, premultiply_alpha, flip_y); 919 destination_gl, video_frame.get(), SingleFrameForWebGL, texture,
920 internal_format, format, type, premultiply_alpha, flip_y);
860 } 921 }
861 922
862 return true; 923 return true;
863 } 924 }
864 925
865 bool SkCanvasVideoRenderer::TexImage2D(unsigned target, 926 bool SkCanvasVideoRenderer::TexImage2D(unsigned target,
866 gpu::gles2::GLES2Interface* gl, 927 gpu::gles2::GLES2Interface* gl,
867 VideoFrame* frame, 928 VideoFrame* frame,
868 int level, 929 int level,
869 int internalformat, 930 int internalformat,
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
957 last_image_->bounds().contains(visible_rect)) { 1018 last_image_->bounds().contains(visible_rect)) {
958 last_image_ = last_image_->makeSubset(visible_rect); 1019 last_image_ = last_image_->makeSubset(visible_rect);
959 } 1020 }
960 } 1021 }
961 1022
962 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() { 1023 SkISize SkCanvasVideoRenderer::LastImageDimensionsForTesting() {
963 return last_image_dimensions_for_testing_; 1024 return last_image_dimensions_for_testing_;
964 } 1025 }
965 1026
966 } // namespace media 1027 } // namespace media
OLDNEW
« no previous file with comments | « media/renderers/skcanvas_video_renderer.h ('k') | third_party/WebKit/Source/core/html/HTMLVideoElement.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698