OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "remoting/client/gl_render_layer.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "remoting/client/gl_canvas.h" | |
9 #include "remoting/client/gl_helpers.h" | |
10 | |
11 | |
12 namespace remoting { | |
13 | |
14 namespace { | |
15 | |
16 // Assign texture coordinates to buffers for use in shader program. | |
17 const float kVertices[] = { | |
18 // Points order: upper-left, bottom-left, upper-right, bottom-right. | |
19 | |
20 // Positions to draw the texture on the normalized canvas coordinate. | |
21 0, 0, 0, 0, 0, 0, 0, 0, | |
22 | |
23 // Region of the texture to be used (normally the whole texture). | |
24 0, 0, 0, 1, 1, 0, 1, 1}; | |
25 | |
26 const int kDefaultUpdateBufferCapacity = | |
27 2048 * 2048 * GlRenderLayer::kBytesPerPixel; | |
28 | |
29 void PackDirtyRegion(uint8_t* dest, | |
30 const uint8_t* source, | |
31 int width, | |
32 int height, | |
33 int stride) { | |
34 for (int i = 0; i < height; i++) { | |
35 memcpy(dest, source, width * GlRenderLayer::kBytesPerPixel); | |
36 source += stride; | |
37 dest += GlRenderLayer::kBytesPerPixel * width; | |
38 } | |
39 } | |
40 | |
41 } // namespace | |
42 | |
43 GlRenderLayer::GlRenderLayer(int texture_id, GlCanvas* canvas) | |
44 : texture_id_(texture_id), canvas_(canvas) { | |
45 texture_handle_ = CreateTexture(); | |
46 buffer_handle_ = CreateBuffer(kVertices, sizeof(kVertices)); | |
47 } | |
48 | |
49 GlRenderLayer::~GlRenderLayer() { | |
50 DCHECK(thread_checker_.CalledOnValidThread()); | |
51 glDeleteBuffers(1, &buffer_handle_); | |
52 glDeleteTextures(1, &texture_handle_); | |
53 } | |
54 | |
55 void GlRenderLayer::SetTexture(const uint8_t* texture, | |
56 int width, | |
57 int height, | |
58 int stride) { | |
59 DCHECK(thread_checker_.CalledOnValidThread()); | |
60 CHECK(width > 0 && height > 0); | |
61 texture_set_ = true; | |
62 glActiveTexture(GL_TEXTURE0 + texture_id_); | |
63 glBindTexture(GL_TEXTURE_2D, texture_handle_); | |
64 | |
65 bool should_reset_row_length; | |
66 const void* buffer_to_update = PrepareTextureBuffer( | |
67 texture, width, height, stride, &should_reset_row_length); | |
68 | |
69 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, | |
70 GL_UNSIGNED_BYTE, buffer_to_update); | |
71 | |
72 if (should_reset_row_length) { | |
73 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
74 } | |
75 | |
76 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
77 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
78 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
80 | |
81 glBindTexture(GL_TEXTURE_2D, 0); | |
82 } | |
83 | |
84 void GlRenderLayer::UpdateTexture(const uint8_t* subtexture, | |
85 int offset_x, | |
86 int offset_y, | |
87 int width, | |
88 int height, | |
89 int stride) { | |
90 DCHECK(thread_checker_.CalledOnValidThread()); | |
91 DCHECK(texture_set_); | |
92 DCHECK(width > 0 && height > 0); | |
93 glActiveTexture(GL_TEXTURE0 + texture_id_); | |
94 glBindTexture(GL_TEXTURE_2D, texture_handle_); | |
95 | |
96 bool should_reset_row_length; | |
97 const void* buffer_to_update = PrepareTextureBuffer( | |
98 subtexture, width, height, stride, &should_reset_row_length); | |
99 | |
100 glTexSubImage2D(GL_TEXTURE_2D, 0, offset_x, offset_y, width, height, GL_RGBA, | |
101 GL_UNSIGNED_BYTE, buffer_to_update); | |
102 | |
103 if (should_reset_row_length) { | |
104 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | |
105 } | |
106 | |
107 glBindTexture(GL_TEXTURE_2D, 0); | |
108 } | |
109 | |
110 void GlRenderLayer::SetVertexPositions(const std::array<float, 8>& positions) { | |
111 DCHECK(thread_checker_.CalledOnValidThread()); | |
112 glBindBuffer(GL_ARRAY_BUFFER, buffer_handle_); | |
113 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(kVertices) / 2, positions.data()); | |
114 glBindBuffer(GL_ARRAY_BUFFER, 0); | |
115 vertex_position_set_ = true; | |
116 } | |
117 | |
118 void GlRenderLayer::SetTextureVisibleArea( | |
119 const std::array<float, 8>& positions) { | |
120 DCHECK(thread_checker_.CalledOnValidThread()); | |
121 glBindBuffer(GL_ARRAY_BUFFER, buffer_handle_); | |
122 glBufferSubData(GL_ARRAY_BUFFER, sizeof(kVertices) / 2, sizeof(kVertices) / 2, | |
123 positions.data()); | |
124 glBindBuffer(GL_ARRAY_BUFFER, 0); | |
125 } | |
126 | |
127 void GlRenderLayer::Draw(float alpha_multiplier) { | |
128 DCHECK(thread_checker_.CalledOnValidThread()); | |
129 DCHECK(texture_set_ && vertex_position_set_); | |
130 canvas_->DrawTexture(texture_id_, texture_handle_, buffer_handle_, | |
131 alpha_multiplier); | |
132 } | |
133 | |
134 const uint8_t* GlRenderLayer::PrepareTextureBuffer( | |
135 const uint8_t* data, | |
136 int width, | |
137 int height, | |
138 int stride, | |
139 bool* should_reset_row_length) { | |
140 *should_reset_row_length = false; | |
141 | |
142 bool stride_multiple_of_bytes_per_pixel = stride % kBytesPerPixel == 0; | |
143 bool loosely_packed = !stride_multiple_of_bytes_per_pixel || | |
144 (stride > 0 && stride != kBytesPerPixel * width); | |
145 | |
146 if (!loosely_packed) { | |
147 return data; | |
148 } | |
149 | |
150 if (stride_multiple_of_bytes_per_pixel && canvas_->GetGlVersion() >= 3) { | |
151 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / kBytesPerPixel); | |
152 *should_reset_row_length = true; | |
153 return data; | |
154 } | |
155 | |
156 // Doesn't support GL_UNPACK_ROW_LENGTH or stride not multiple of | |
157 // kBytesPerPixel. Manually pack the data. | |
158 int required_size = width * height * kBytesPerPixel; | |
159 if (update_buffer_size_ < required_size) { | |
160 if (required_size < kDefaultUpdateBufferCapacity) { | |
161 update_buffer_size_ = kDefaultUpdateBufferCapacity; | |
162 } else { | |
163 update_buffer_size_ = required_size; | |
164 } | |
165 update_buffer_.reset(new uint8_t[update_buffer_size_]); | |
166 } | |
167 PackDirtyRegion(update_buffer_.get(), data, width, height, stride); | |
168 return update_buffer_.get(); | |
169 } | |
170 | |
171 } // namespace remoting | |
OLD | NEW |