8 #include "effect_util.h"
9 #include "resource_pool.h"
12 #include "ycbcr_input.h"
14 using namespace Eigen;
19 YCbCrInput::YCbCrInput(const ImageFormat &image_format,
20 const YCbCrFormat &ycbcr_format,
21 unsigned width, unsigned height,
22 YCbCrInputSplitting ycbcr_input_splitting,
24 : image_format(image_format),
25 ycbcr_format(ycbcr_format),
26 ycbcr_input_splitting(ycbcr_input_splitting),
31 resource_pool(nullptr)
33 pbos[0] = pbos[1] = pbos[2] = 0;
34 texture_num[0] = texture_num[1] = texture_num[2] = 0;
39 pixel_data[0] = pixel_data[1] = pixel_data[2] = nullptr;
40 owns_texture[0] = owns_texture[1] = owns_texture[2] = false;
42 register_uniform_sampler2d("tex_y", &uniform_tex_y);
44 if (ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) {
46 assert(ycbcr_format.chroma_subsampling_x == 1);
47 assert(ycbcr_format.chroma_subsampling_y == 1);
48 } else if (ycbcr_input_splitting == YCBCR_INPUT_SPLIT_Y_AND_CBCR) {
50 register_uniform_sampler2d("tex_cbcr", &uniform_tex_cb);
52 assert(ycbcr_input_splitting == YCBCR_INPUT_PLANAR);
54 register_uniform_sampler2d("tex_cb", &uniform_tex_cb);
55 register_uniform_sampler2d("tex_cr", &uniform_tex_cr);
58 register_int("needs_mipmaps", &needs_mipmaps);
59 register_uniform_mat3("inv_ycbcr_matrix", &uniform_ycbcr_matrix);
60 register_uniform_vec3("offset", uniform_offset);
61 register_uniform_vec2("cb_offset", (float *)&uniform_cb_offset);
62 register_uniform_vec2("cr_offset", (float *)&uniform_cr_offset);
65 YCbCrInput::~YCbCrInput()
67 for (unsigned channel = 0; channel < num_channels; ++channel) {
68 possibly_release_texture(channel);
72 void YCbCrInput::set_gl_state(GLuint glsl_program_num, const string& prefix, unsigned *sampler_num)
74 compute_ycbcr_matrix(ycbcr_format, uniform_offset, &uniform_ycbcr_matrix, type);
76 uniform_cb_offset.x = compute_chroma_offset(
77 ycbcr_format.cb_x_position, ycbcr_format.chroma_subsampling_x, widths[1]);
78 uniform_cb_offset.y = compute_chroma_offset(
79 ycbcr_format.cb_y_position, ycbcr_format.chroma_subsampling_y, heights[1]);
81 uniform_cr_offset.x = compute_chroma_offset(
82 ycbcr_format.cr_x_position, ycbcr_format.chroma_subsampling_x, widths[2]);
83 uniform_cr_offset.y = compute_chroma_offset(
84 ycbcr_format.cr_y_position, ycbcr_format.chroma_subsampling_y, heights[2]);
86 for (unsigned channel = 0; channel < num_channels; ++channel) {
87 glActiveTexture(GL_TEXTURE0 + *sampler_num + channel);
90 if (texture_num[channel] == 0 && (pbos[channel] != 0 || pixel_data[channel] != nullptr)) {
91 GLenum format, internal_format;
92 if (channel == 0 && ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) {
93 if (type == GL_UNSIGNED_INT_2_10_10_10_REV) {
95 internal_format = GL_RGB10_A2;
96 } else if (type == GL_UNSIGNED_SHORT) {
98 internal_format = GL_RGB16;
100 assert(type == GL_UNSIGNED_BYTE);
102 internal_format = GL_RGB8;
104 } else if (channel == 1 && ycbcr_input_splitting == YCBCR_INPUT_SPLIT_Y_AND_CBCR) {
106 if (type == GL_UNSIGNED_SHORT) {
107 internal_format = GL_RG16;
109 assert(type == GL_UNSIGNED_BYTE);
110 internal_format = GL_RG8;
114 if (type == GL_UNSIGNED_SHORT) {
115 internal_format = GL_R16;
117 assert(type == GL_UNSIGNED_BYTE);
118 internal_format = GL_R8;
122 // (Re-)upload the texture.
123 texture_num[channel] = resource_pool->create_2d_texture(internal_format, widths[channel], heights[channel]);
124 glBindTexture(GL_TEXTURE_2D, texture_num[channel]);
126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, needs_mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
128 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbos[channel]);
130 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
132 glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch[channel]);
134 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widths[channel], heights[channel], format, type, pixel_data[channel]);
136 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
139 glGenerateMipmap(GL_TEXTURE_2D);
142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
146 owns_texture[channel] = true;
148 glBindTexture(GL_TEXTURE_2D, texture_num[channel]);
150 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, needs_mipmaps ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
155 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
159 uniform_tex_y = *sampler_num + 0;
160 if (ycbcr_input_splitting != YCBCR_INPUT_INTERLEAVED) {
161 uniform_tex_cb = *sampler_num + 1;
163 if (ycbcr_input_splitting == YCBCR_INPUT_PLANAR) {
164 uniform_tex_cr = *sampler_num + 2;
167 *sampler_num += num_channels;
170 string YCbCrInput::output_fragment_shader()
174 if (ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) {
175 frag_shader += "#define Y_CB_CR_SAME_TEXTURE 1\n";
176 } else if (ycbcr_input_splitting == YCBCR_INPUT_SPLIT_Y_AND_CBCR) {
177 cb_cr_offsets_equal =
178 (fabs(ycbcr_format.cb_x_position - ycbcr_format.cr_x_position) < 1e-6) &&
179 (fabs(ycbcr_format.cb_y_position - ycbcr_format.cr_y_position) < 1e-6);
181 snprintf(buf, sizeof(buf), "#define Y_CB_CR_SAME_TEXTURE 0\n#define CB_CR_SAME_TEXTURE 1\n#define CB_CR_OFFSETS_EQUAL %d\n",
182 cb_cr_offsets_equal);
185 frag_shader += "#define Y_CB_CR_SAME_TEXTURE 0\n#define CB_CR_SAME_TEXTURE 0\n";
188 frag_shader += read_file("ycbcr_input.frag");
189 frag_shader += "#undef CB_CR_SAME_TEXTURE\n#undef Y_CB_CR_SAME_TEXTURE\n";
193 void YCbCrInput::change_ycbcr_format(const YCbCrFormat &ycbcr_format)
195 if (ycbcr_input_splitting == YCBCR_INPUT_SPLIT_Y_AND_CBCR && cb_cr_offsets_equal) {
196 assert((fabs(ycbcr_format.cb_x_position - ycbcr_format.cr_x_position) < 1e-6) &&
197 (fabs(ycbcr_format.cb_y_position - ycbcr_format.cr_y_position) < 1e-6));
199 if (ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) {
200 assert(ycbcr_format.chroma_subsampling_x == 1);
201 assert(ycbcr_format.chroma_subsampling_y == 1);
203 this->ycbcr_format = ycbcr_format;
206 void YCbCrInput::invalidate_pixel_data()
208 for (unsigned channel = 0; channel < 3; ++channel) {
209 possibly_release_texture(channel);
213 bool YCbCrInput::set_int(const std::string& key, int value)
215 if (key == "needs_mipmaps") {
216 if (ycbcr_input_splitting != YCBCR_INPUT_INTERLEAVED && value != 0) {
217 // We do not currently support this.
221 return Effect::set_int(key, value);
224 void YCbCrInput::possibly_release_texture(unsigned channel)
226 if (texture_num[channel] != 0 && owns_texture[channel]) {
227 resource_pool->release_2d_texture(texture_num[channel]);
228 texture_num[channel] = 0;
229 owns_texture[channel] = false;