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]);
153 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
157 uniform_tex_y = *sampler_num + 0;
158 if (ycbcr_input_splitting != YCBCR_INPUT_INTERLEAVED) {
159 uniform_tex_cb = *sampler_num + 1;
161 if (ycbcr_input_splitting == YCBCR_INPUT_PLANAR) {
162 uniform_tex_cr = *sampler_num + 2;
165 *sampler_num += num_channels;
168 string YCbCrInput::output_fragment_shader()
172 if (ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) {
173 frag_shader += "#define Y_CB_CR_SAME_TEXTURE 1\n";
174 } else if (ycbcr_input_splitting == YCBCR_INPUT_SPLIT_Y_AND_CBCR) {
175 cb_cr_offsets_equal =
176 (fabs(ycbcr_format.cb_x_position - ycbcr_format.cr_x_position) < 1e-6) &&
177 (fabs(ycbcr_format.cb_y_position - ycbcr_format.cr_y_position) < 1e-6);
179 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",
180 cb_cr_offsets_equal);
183 frag_shader += "#define Y_CB_CR_SAME_TEXTURE 0\n#define CB_CR_SAME_TEXTURE 0\n";
186 frag_shader += read_file("ycbcr_input.frag");
187 frag_shader += "#undef CB_CR_SAME_TEXTURE\n#undef Y_CB_CR_SAME_TEXTURE\n";
191 void YCbCrInput::change_ycbcr_format(const YCbCrFormat &ycbcr_format)
193 if (cb_cr_offsets_equal) {
194 assert((fabs(ycbcr_format.cb_x_position - ycbcr_format.cr_x_position) < 1e-6) &&
195 (fabs(ycbcr_format.cb_y_position - ycbcr_format.cr_y_position) < 1e-6));
197 if (ycbcr_input_splitting == YCBCR_INPUT_INTERLEAVED) {
198 assert(ycbcr_format.chroma_subsampling_x == 1);
199 assert(ycbcr_format.chroma_subsampling_y == 1);
201 this->ycbcr_format = ycbcr_format;
204 void YCbCrInput::invalidate_pixel_data()
206 for (unsigned channel = 0; channel < 3; ++channel) {
207 possibly_release_texture(channel);
211 bool YCbCrInput::set_int(const std::string& key, int value)
213 if (key == "needs_mipmaps") {
214 if (ycbcr_input_splitting != YCBCR_INPUT_INTERLEAVED && value != 0) {
215 // We do not currently support this.
219 return Effect::set_int(key, value);
222 void YCbCrInput::possibly_release_texture(unsigned channel)
224 if (texture_num[channel] != 0 && owns_texture[channel]) {
225 resource_pool->release_2d_texture(texture_num[channel]);
226 texture_num[channel] = 0;
227 owns_texture[channel] = false;