+void ensure_texture_resolution(PBOFrameAllocator::Userdata *userdata, unsigned field, unsigned width, unsigned height, unsigned cbcr_width, unsigned cbcr_height, unsigned v210_width)
+{
+ bool first;
+ switch (userdata->pixel_format) {
+ case PixelFormat_10BitYCbCr:
+ first = userdata->tex_v210[field] == 0 || userdata->tex_444[field] == 0;
+ break;
+ case PixelFormat_8BitYCbCr:
+ first = userdata->tex_y[field] == 0 || userdata->tex_cbcr[field] == 0;
+ break;
+ case PixelFormat_8BitBGRA:
+ first = userdata->tex_rgba[field] == 0;
+ break;
+ case PixelFormat_8BitYCbCrPlanar:
+ first = userdata->tex_y[field] == 0 || userdata->tex_cb[field] == 0 || userdata->tex_cr[field] == 0;
+ break;
+ default:
+ assert(false);
+ }
+
+ if (first ||
+ width != userdata->last_width[field] ||
+ height != userdata->last_height[field] ||
+ cbcr_width != userdata->last_cbcr_width[field] ||
+ cbcr_height != userdata->last_cbcr_height[field]) {
+ // We changed resolution since last use of this texture, so we need to create
+ // a new object. Note that this each card has its own PBOFrameAllocator,
+ // we don't need to worry about these flip-flopping between resolutions.
+ switch (userdata->pixel_format) {
+ case PixelFormat_10BitYCbCr:
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_444[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, nullptr);
+ check_error();
+ break;
+ case PixelFormat_8BitYCbCr: {
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_cbcr[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, cbcr_width, height, 0, GL_RG, GL_UNSIGNED_BYTE, nullptr);
+ check_error();
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_y[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+ check_error();
+ break;
+ }
+ case PixelFormat_8BitYCbCrPlanar: {
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_y[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+ check_error();
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_cb[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, cbcr_width, cbcr_height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+ check_error();
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_cr[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, cbcr_width, cbcr_height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
+ check_error();
+ break;
+ }
+ case PixelFormat_8BitBGRA:
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_rgba[field]);
+ check_error();
+ if (global_flags.can_disable_srgb_decoder) { // See the comments in tweaked_inputs.h.
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
+ }
+ check_error();
+ break;
+ }
+ userdata->last_width[field] = width;
+ userdata->last_height[field] = height;
+ userdata->last_cbcr_width[field] = cbcr_width;
+ userdata->last_cbcr_height[field] = cbcr_height;
+ }
+ if (global_flags.ten_bit_input &&
+ (first || v210_width != userdata->last_v210_width[field])) {
+ // Same as above; we need to recreate the texture.
+ glBindTexture(GL_TEXTURE_2D, userdata->tex_v210[field]);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, v210_width, height, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, nullptr);
+ check_error();
+ userdata->last_v210_width[field] = v210_width;
+ }
+}
+
+void upload_texture(GLuint tex, GLuint width, GLuint height, GLuint stride, bool interlaced_stride, GLenum format, GLenum type, GLintptr offset)