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

Side by Side Diff: gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc

Issue 2760843002: Add readback path for CopyTextureCHROMIUM (Closed)
Patch Set: use pack/unpack buffer 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 "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h" 5 #include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
(...skipping 599 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 source_y, source_width, source_height); 610 source_y, source_width, source_height);
611 } 611 }
612 612
613 decoder->RestoreTextureState(source_id); 613 decoder->RestoreTextureState(source_id);
614 decoder->RestoreTextureState(dest_id); 614 decoder->RestoreTextureState(dest_id);
615 decoder->RestoreTextureUnitBindings(0); 615 decoder->RestoreTextureUnitBindings(0);
616 decoder->RestoreActiveTexture(); 616 decoder->RestoreActiveTexture();
617 decoder->RestoreFramebufferBindings(); 617 decoder->RestoreFramebufferBindings();
618 } 618 }
619 619
620 // Convert RGBA/UNSIGNED_BYTE source to RGB/UNSIGNED_BYTE destination.
621 void convertToRGB(const uint8_t* source,
622 uint8_t* destination,
623 unsigned length) {
624 for (unsigned i = 0; i < length; ++i) {
625 destination[0] = source[0];
626 destination[1] = source[1];
627 destination[2] = source[2];
628 source += 4;
629 destination += 3;
630 }
631 }
632
633 // Convert RGBA/UNSIGNED_BYTE source to RGB/FLOAT destination.
634 void convertToRGBFloat(const uint8_t* source,
635 float* destination,
636 unsigned length) {
637 const float scaleFactor = 1.0f / 255.0f;
638 for (unsigned i = 0; i < length; ++i) {
639 destination[0] = source[0] * scaleFactor;
640 destination[1] = source[1] * scaleFactor;
641 destination[2] = source[2] * scaleFactor;
642 source += 4;
643 destination += 3;
644 }
645 }
646
647 // Prepare the image data to be uploaded to a texture in pixel unpack buffer.
648 void prepareUnpackBuffer(GLuint buffer[2],
649 bool is_es,
650 GLenum format,
651 GLenum type,
652 GLsizei width,
653 GLsizei height) {
654 uint32_t pixel_num = width * height;
655
656 // Result of glReadPixels with format == GL_RGB and type == GL_UNSIGNED_BYTE
657 // from read framebuffer in RGBA fromat is not correct on desktop core
658 // profile on both Linux Mesa and Linux NVIDIA. This may be a driver bug.
659 bool is_rgb_unsigned_byte = format == GL_RGB && type == GL_UNSIGNED_BYTE;
660 if ((!is_es && !is_rgb_unsigned_byte) ||
661 (format == GL_RGBA && type == GL_UNSIGNED_BYTE)) {
662 uint32_t bytes_per_group =
663 gpu::gles2::GLES2Util::ComputeImageGroupSize(format, type);
664 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer[0]);
665 glBufferData(GL_PIXEL_PACK_BUFFER, pixel_num * bytes_per_group, 0,
666 GL_STATIC_READ);
667 glReadPixels(0, 0, width, height, format, type, 0);
668 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[0]);
669 return;
670 }
671
672 uint32_t bytes_per_group =
673 gpu::gles2::GLES2Util::ComputeImageGroupSize(GL_RGBA, GL_UNSIGNED_BYTE);
674 uint32_t buf_size = pixel_num * bytes_per_group;
675
676 if (format == GL_RGB && type == GL_FLOAT) {
677 #if defined(OS_ANDROID)
678 // Reading pixels to pbo with glReadPixels will cause random failures of
679 // GLCopyTextureCHROMIUMES3Test.FormatCombinations in gl_tests. This is seen
680 // on Nexus 5 but not Nexus 4. Read pixels to client memory, then upload to
681 // pixel unpack buffer with glBufferData.
qiankun 2017/03/29 09:00:10 I spent a lot of time on investigating this issue
Zhenyao Mo 2017/03/29 17:29:34 This sounds like a memory corruption Qualcomm driv
qiankun 2017/03/30 07:56:07 I see. Thanks for pointing it out to me. Per my te
682 std::unique_ptr<uint8_t[]> pixels(new uint8_t[width * height * 4]);
683 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
684 std::unique_ptr<float[]> data(new float[width * height * 3]);
685 convertToRGBFloat(pixels.get(), data.get(), pixel_num);
686 bytes_per_group =
687 gpu::gles2::GLES2Util::ComputeImageGroupSize(format, type);
688 buf_size = pixel_num * bytes_per_group;
689 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[1]);
690 glBufferData(GL_PIXEL_UNPACK_BUFFER, buf_size, data.get(), GL_STATIC_DRAW);
691 #else
692 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer[0]);
693 glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, 0, GL_STATIC_READ);
694 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
695 uint8_t* pixels = (uint8_t*)glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0,
Zhenyao Mo 2017/03/29 17:29:34 This is against chromium coding style. Use cast.
qiankun 2017/03/30 07:56:07 Done.
696 buf_size, GL_MAP_READ_BIT);
697
698 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[1]);
699 bytes_per_group =
700 gpu::gles2::GLES2Util::ComputeImageGroupSize(format, type);
701 buf_size = pixel_num * bytes_per_group;
702 glBufferData(GL_PIXEL_UNPACK_BUFFER, buf_size, 0, GL_STATIC_DRAW);
703 float* data = (float*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, buf_size,
Zhenyao Mo 2017/03/29 17:29:34 Same here, use cast.
qiankun 2017/03/30 07:56:07 Done.
704 GL_MAP_WRITE_BIT);
Zhenyao Mo 2017/03/29 17:29:34 Combine with GL_MAP_INVALIDATE_BUFFER_BIT and see
qiankun 2017/03/30 07:56:07 The GL_MAP_INVALIDATE_BUFFER_BIT didn't have perfo
Zhenyao Mo 2017/03/30 17:08:02 That's quite the opposite from what we would expec
705 convertToRGBFloat(pixels, data, pixel_num);
706 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
707 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
708 #endif
709 return;
710 }
711
712 if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
713 glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer[0]);
714 glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, 0, GL_DYNAMIC_DRAW);
715 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
716 void* pixels = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, buf_size,
717 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT);
718 void* data = pixels;
719 convertToRGB((uint8_t*)pixels, (uint8_t*)data, pixel_num);
720 glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
721 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer[0]);
722 return;
723 }
724
725 NOTREACHED();
726 }
727
728 void DoReadbackAndTexImage(bool is_tex_image,
Zhenyao Mo 2017/03/29 17:29:34 It's better to define enum { kTexImage, kTexSubIma
qiankun 2017/03/30 07:56:07 Done.
729 const gpu::gles2::GLES2Decoder* decoder,
730 GLenum source_target,
731 GLuint source_id,
732 GLint source_level,
733 GLenum dest_target,
734 GLuint dest_id,
735 GLint dest_level,
736 GLenum dest_internal_format,
737 GLint xoffset,
738 GLint yoffset,
739 GLsizei width,
740 GLsizei height,
741 GLuint framebuffer) {
742 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), source_target);
743 GLenum dest_binding_target =
744 gpu::gles2::GLES2Util::GLFaceTargetToTextureTarget(dest_target);
745 DCHECK(dest_binding_target == GL_TEXTURE_2D ||
746 dest_binding_target == GL_TEXTURE_CUBE_MAP);
747 DCHECK(source_level == 0 || decoder->GetFeatureInfo()->IsES3Capable());
748 if (BindFramebufferTexture2D(source_target, source_id, source_level,
749 framebuffer)) {
750 glBindTexture(dest_binding_target, dest_id);
751 glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
752 glTexParameterf(dest_binding_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
753 glTexParameteri(dest_binding_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
754 glTexParameteri(dest_binding_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
755
756 GLenum format = GL_RGBA;
757 GLenum type = GL_UNSIGNED_BYTE;
758 switch (dest_internal_format) {
759 case GL_RGB9_E5:
760 format = GL_RGB;
761 type = GL_FLOAT;
762 break;
763 case GL_SRGB_EXT:
764 case GL_SRGB8:
765 format = GL_RGB;
766 break;
767 case GL_RGB5_A1:
768 case GL_SRGB_ALPHA_EXT:
769 case GL_SRGB8_ALPHA8:
770 break;
771 default:
772 NOTREACHED();
773 break;
774 }
775
776 // TODO(qiankun.miao@intel.com): PIXEL_PACK_BUFFER and PIXEL_UNPACK_BUFFER
777 // are not supported in ES2.
778 bool is_es = decoder->GetFeatureInfo()->gl_version_info().is_es;
779 DCHECK(!is_es || decoder->GetFeatureInfo()->gl_version_info().is_es3);
Zhenyao Mo 2017/03/29 17:29:34 You can just DCHECK(!decoder->GetFeatureInfo()->gl
qiankun 2017/03/30 07:56:07 Done.
780
781 uint32_t buffer_num = is_es && format == GL_RGB && type == GL_FLOAT ? 2 : 1;
782 GLuint buffer[2];
Zhenyao Mo 2017/03/29 17:29:34 Initialize buffer[0] and buffer[1] to 0.
qiankun 2017/03/30 07:56:07 Done.
783 glGenBuffersARB(buffer_num, buffer);
784 prepareUnpackBuffer(buffer, is_es, format, type, width, height);
785
786 if (is_tex_image) {
787 glTexImage2D(dest_target, dest_level, dest_internal_format, width, height,
788 0, format, type, 0);
789 } else {
790 glTexSubImage2D(dest_target, dest_level, xoffset, yoffset, width, height,
791 format, type, 0);
792 }
793 glDeleteBuffersARB(buffer_num, buffer);
794 }
795
796 decoder->RestoreTextureState(source_id);
797 decoder->RestoreTextureState(dest_id);
798 decoder->RestoreTextureUnitBindings(0);
799 decoder->RestoreActiveTexture();
800 decoder->RestoreFramebufferBindings();
801 decoder->RestoreBufferBindings();
802 }
803
620 } // namespace 804 } // namespace
621 805
622 namespace gpu { 806 namespace gpu {
623 namespace gles2 { 807 namespace gles2 {
624 808
625 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager() 809 CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
626 : initialized_(false), 810 : initialized_(false),
627 nv_egl_stream_consumer_external_(false), 811 nv_egl_stream_consumer_external_(false),
628 vertex_shaders_(kNumVertexShaders, 0u), 812 vertex_shaders_(kNumVertexShaders, 0u),
629 fragment_shaders_(kNumFragmentShaders, 0u), 813 fragment_shaders_(kNumFragmentShaders, 0u),
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 width, height, framebuffer_); 912 width, height, framebuffer_);
729 return; 913 return;
730 } 914 }
731 915
732 // Draw to level 0 of an intermediate GL_TEXTURE_2D texture. 916 // Draw to level 0 of an intermediate GL_TEXTURE_2D texture.
733 GLuint dest_texture = dest_id; 917 GLuint dest_texture = dest_id;
734 GLuint intermediate_texture = 0; 918 GLuint intermediate_texture = 0;
735 GLint original_dest_level = dest_level; 919 GLint original_dest_level = dest_level;
736 GLenum original_dest_target = dest_target; 920 GLenum original_dest_target = dest_target;
737 GLenum original_internal_format = dest_internal_format; 921 GLenum original_internal_format = dest_internal_format;
738 if (method == DRAW_AND_COPY) { 922 if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) {
739 GLenum adjusted_internal_format = 923 GLenum adjusted_internal_format =
740 getIntermediateFormat(dest_internal_format); 924 method == DRAW_AND_READBACK
925 ? GL_RGBA
926 : getIntermediateFormat(dest_internal_format);
741 dest_target = GL_TEXTURE_2D; 927 dest_target = GL_TEXTURE_2D;
742 glGenTextures(1, &intermediate_texture); 928 glGenTextures(1, &intermediate_texture);
743 glBindTexture(dest_target, intermediate_texture); 929 glBindTexture(dest_target, intermediate_texture);
744 GLenum format = TextureManager::ExtractFormatFromStorageFormat( 930 GLenum format = TextureManager::ExtractFormatFromStorageFormat(
745 adjusted_internal_format); 931 adjusted_internal_format);
746 GLenum type = 932 GLenum type =
747 TextureManager::ExtractTypeFromStorageFormat(adjusted_internal_format); 933 TextureManager::ExtractTypeFromStorageFormat(adjusted_internal_format);
748 934
749 glTexImage2D(dest_target, 0, adjusted_internal_format, width, height, 0, 935 glTexImage2D(dest_target, 0, adjusted_internal_format, width, height, 0,
750 format, type, nullptr); 936 format, type, nullptr);
751 dest_texture = intermediate_texture; 937 dest_texture = intermediate_texture;
752 dest_level = 0; 938 dest_level = 0;
753 dest_internal_format = adjusted_internal_format; 939 dest_internal_format = adjusted_internal_format;
754 } 940 }
755 // Use kIdentityMatrix if no transform passed in. 941 // Use kIdentityMatrix if no transform passed in.
756 DoCopyTextureWithTransform( 942 DoCopyTextureWithTransform(
757 decoder, source_target, source_id, source_level, source_internal_format, 943 decoder, source_target, source_id, source_level, source_internal_format,
758 dest_target, dest_texture, dest_level, dest_internal_format, width, 944 dest_target, dest_texture, dest_level, dest_internal_format, width,
759 height, flip_y, premultiply_alpha, unpremultiply_alpha, kIdentityMatrix); 945 height, flip_y, premultiply_alpha, unpremultiply_alpha, kIdentityMatrix);
760 946
761 if (method == DRAW_AND_COPY) { 947 if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) {
762 source_level = 0; 948 source_level = 0;
763 DoCopyTexImage2D(decoder, dest_target, intermediate_texture, source_level, 949 if (method == DRAW_AND_COPY) {
764 original_dest_target, dest_id, original_dest_level, 950 DoCopyTexImage2D(decoder, dest_target, intermediate_texture, source_level,
765 original_internal_format, width, height, framebuffer_); 951 original_dest_target, dest_id, original_dest_level,
952 original_internal_format, width, height, framebuffer_);
953 } else if (method == DRAW_AND_READBACK) {
954 DoReadbackAndTexImage(true, decoder, dest_target, intermediate_texture,
955 source_level, original_dest_target, dest_id,
956 original_dest_level, original_internal_format, 0, 0,
957 width, height, framebuffer_);
958 }
766 glDeleteTextures(1, &intermediate_texture); 959 glDeleteTextures(1, &intermediate_texture);
767 } 960 }
768 } 961 }
769 962
770 void CopyTextureCHROMIUMResourceManager::DoCopySubTexture( 963 void CopyTextureCHROMIUMResourceManager::DoCopySubTexture(
771 const gles2::GLES2Decoder* decoder, 964 const gles2::GLES2Decoder* decoder,
772 GLenum source_target, 965 GLenum source_target,
773 GLuint source_id, 966 GLuint source_id,
774 GLint source_level, 967 GLint source_level,
775 GLenum source_internal_format, 968 GLenum source_internal_format,
(...skipping 22 matching lines...) Expand all
798 return; 991 return;
799 } 992 }
800 993
801 // Draw to level 0 of an intermediate GL_TEXTURE_2D texture. 994 // Draw to level 0 of an intermediate GL_TEXTURE_2D texture.
802 GLint dest_xoffset = xoffset; 995 GLint dest_xoffset = xoffset;
803 GLint dest_yoffset = yoffset; 996 GLint dest_yoffset = yoffset;
804 GLuint dest_texture = dest_id; 997 GLuint dest_texture = dest_id;
805 GLint original_dest_level = dest_level; 998 GLint original_dest_level = dest_level;
806 GLenum original_dest_target = dest_target; 999 GLenum original_dest_target = dest_target;
807 GLuint intermediate_texture = 0; 1000 GLuint intermediate_texture = 0;
808 if (method == DRAW_AND_COPY) { 1001 GLenum original_internal_format = dest_internal_format;
1002 if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) {
809 GLenum adjusted_internal_format = 1003 GLenum adjusted_internal_format =
810 getIntermediateFormat(dest_internal_format); 1004 method == DRAW_AND_READBACK
1005 ? GL_RGBA
1006 : getIntermediateFormat(dest_internal_format);
811 dest_target = GL_TEXTURE_2D; 1007 dest_target = GL_TEXTURE_2D;
812 glGenTextures(1, &intermediate_texture); 1008 glGenTextures(1, &intermediate_texture);
813 glBindTexture(dest_target, intermediate_texture); 1009 glBindTexture(dest_target, intermediate_texture);
814 GLenum format = TextureManager::ExtractFormatFromStorageFormat( 1010 GLenum format = TextureManager::ExtractFormatFromStorageFormat(
815 adjusted_internal_format); 1011 adjusted_internal_format);
816 GLenum type = 1012 GLenum type =
817 TextureManager::ExtractTypeFromStorageFormat(adjusted_internal_format); 1013 TextureManager::ExtractTypeFromStorageFormat(adjusted_internal_format);
818 1014
819 glTexImage2D(dest_target, 0, adjusted_internal_format, width, height, 0, 1015 glTexImage2D(dest_target, 0, adjusted_internal_format, width, height, 0,
820 format, type, nullptr); 1016 format, type, nullptr);
821 dest_texture = intermediate_texture; 1017 dest_texture = intermediate_texture;
822 dest_level = 0; 1018 dest_level = 0;
823 dest_internal_format = adjusted_internal_format; 1019 dest_internal_format = adjusted_internal_format;
824 dest_xoffset = 0; 1020 dest_xoffset = 0;
825 dest_yoffset = 0; 1021 dest_yoffset = 0;
826 dest_width = width; 1022 dest_width = width;
827 dest_height = height; 1023 dest_height = height;
828 } 1024 }
829 1025
830 DoCopySubTextureWithTransform( 1026 DoCopySubTextureWithTransform(
831 decoder, source_target, source_id, source_level, source_internal_format, 1027 decoder, source_target, source_id, source_level, source_internal_format,
832 dest_target, dest_texture, dest_level, dest_internal_format, dest_xoffset, 1028 dest_target, dest_texture, dest_level, dest_internal_format, dest_xoffset,
833 dest_yoffset, x, y, width, height, dest_width, dest_height, source_width, 1029 dest_yoffset, x, y, width, height, dest_width, dest_height, source_width,
834 source_height, flip_y, premultiply_alpha, unpremultiply_alpha, 1030 source_height, flip_y, premultiply_alpha, unpremultiply_alpha,
835 kIdentityMatrix); 1031 kIdentityMatrix);
836 1032
837 if (method == DRAW_AND_COPY) { 1033 if (method == DRAW_AND_COPY || method == DRAW_AND_READBACK) {
838 source_level = 0; 1034 source_level = 0;
839 DoCopyTexSubImage2D(decoder, dest_target, intermediate_texture, 1035 if (method == DRAW_AND_COPY) {
840 source_level, original_dest_target, dest_id, 1036 DoCopyTexSubImage2D(decoder, dest_target, intermediate_texture,
841 original_dest_level, xoffset, yoffset, 0, 0, width, 1037 source_level, original_dest_target, dest_id,
842 height, framebuffer_); 1038 original_dest_level, xoffset, yoffset, 0, 0, width,
1039 height, framebuffer_);
1040 } else if (method == DRAW_AND_READBACK) {
1041 DoReadbackAndTexImage(false, decoder, dest_target, intermediate_texture,
1042 source_level, original_dest_target, dest_id,
1043 original_dest_level, original_internal_format,
1044 xoffset, yoffset, width, height, framebuffer_);
1045 }
843 glDeleteTextures(1, &intermediate_texture); 1046 glDeleteTextures(1, &intermediate_texture);
844 } 1047 }
845 } 1048 }
846 1049
847 void CopyTextureCHROMIUMResourceManager::DoCopySubTextureWithTransform( 1050 void CopyTextureCHROMIUMResourceManager::DoCopySubTextureWithTransform(
848 const gles2::GLES2Decoder* decoder, 1051 const gles2::GLES2Decoder* decoder,
849 GLenum source_target, 1052 GLenum source_target,
850 GLuint source_id, 1053 GLuint source_id,
851 GLint source_level, 1054 GLint source_level,
852 GLenum source_internal_format, 1055 GLenum source_internal_format,
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
1133 decoder->RestoreTextureUnitBindings(0); 1336 decoder->RestoreTextureUnitBindings(0);
1134 decoder->RestoreActiveTexture(); 1337 decoder->RestoreActiveTexture();
1135 decoder->RestoreProgramBindings(); 1338 decoder->RestoreProgramBindings();
1136 decoder->RestoreBufferBindings(); 1339 decoder->RestoreBufferBindings();
1137 decoder->RestoreFramebufferBindings(); 1340 decoder->RestoreFramebufferBindings();
1138 decoder->RestoreGlobalState(); 1341 decoder->RestoreGlobalState();
1139 } 1342 }
1140 1343
1141 } // namespace gles2 1344 } // namespace gles2
1142 } // namespace gpu 1345 } // namespace gpu
OLDNEW
« no previous file with comments | « gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h ('k') | gpu/command_buffer/service/gles2_cmd_decoder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698