+const unsigned const_resource_plane_order_YUV[3] = {
+ 0,
+ 1,
+ 2
+};
+
+const unsigned const_resource_plane_order_YVU[3] = {
+ 0,
+ 2,
+ 1
+};
+
+void
+vl_get_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format,
+ enum pipe_format out_format[VL_NUM_COMPONENTS])
+{
+ unsigned num_planes = util_format_get_num_planes(format);
+ unsigned i;
+
+ for (i = 0; i < num_planes; i++)
+ out_format[i] = util_format_get_plane_format(format, i);
+ for (; i < VL_NUM_COMPONENTS; i++)
+ out_format[i] = PIPE_FORMAT_NONE;
+
+ if (format == PIPE_FORMAT_YUYV)
+ out_format[0] = PIPE_FORMAT_R8G8_R8B8_UNORM;
+ else if (format == PIPE_FORMAT_UYVY)
+ out_format[0] = PIPE_FORMAT_G8R8_B8R8_UNORM;
+}
+
+const unsigned *
+vl_video_buffer_plane_order(enum pipe_format format)
+{
+ switch(format) {
+ case PIPE_FORMAT_YV12:
+ return const_resource_plane_order_YVU;
+
+ case PIPE_FORMAT_NV12:
+ case PIPE_FORMAT_R8G8B8A8_UNORM:
+ case PIPE_FORMAT_B8G8R8A8_UNORM:
+ case PIPE_FORMAT_YUYV:
+ case PIPE_FORMAT_UYVY:
+ case PIPE_FORMAT_P016:
+ return const_resource_plane_order_YUV;
+
+ default:
+ return NULL;
+ }
+}
+
+static enum pipe_format
+vl_video_buffer_surface_format(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+
+ /* a subsampled formats can't work as surface use RGBA instead */
+ if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
+ return PIPE_FORMAT_R8G8B8A8_UNORM;
+
+ return format;
+}
+
+bool
+vl_video_buffer_is_format_supported(struct pipe_screen *screen,
+ enum pipe_format format,
+ enum pipe_video_profile profile,
+ enum pipe_video_entrypoint entrypoint)
+{
+ enum pipe_format resource_formats[VL_NUM_COMPONENTS];
+ unsigned i;
+
+ vl_get_video_buffer_formats(screen, format, resource_formats);
+
+ for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
+ enum pipe_format format = resource_formats[i];
+
+ if (format == PIPE_FORMAT_NONE)
+ continue;
+
+ /* we at least need to sample from it */
+ if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_SAMPLER_VIEW))
+ return false;
+
+ format = vl_video_buffer_surface_format(format);
+ if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, 0, PIPE_BIND_RENDER_TARGET))
+ return false;
+ }
+
+ return true;
+}
+
+unsigned
+vl_video_buffer_max_size(struct pipe_screen *screen)
+{
+ return screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);
+}
+
+void
+vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
+ struct pipe_video_codec *vcodec,
+ void *associated_data,
+ void (*destroy_associated_data)(void *))
+{
+ vbuf->codec = vcodec;
+
+ if (vbuf->associated_data == associated_data)
+ return;
+
+ if (vbuf->associated_data)
+ vbuf->destroy_associated_data(vbuf->associated_data);
+
+ vbuf->associated_data = associated_data;
+ vbuf->destroy_associated_data = destroy_associated_data;
+}
+
+void *
+vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
+ struct pipe_video_codec *vcodec)
+{
+ if (vbuf->codec == vcodec)
+ return vbuf->associated_data;
+ else
+ return NULL;
+}
+
+void
+vl_video_buffer_template(struct pipe_resource *templ,
+ const struct pipe_video_buffer *tmpl,
+ enum pipe_format resource_format,
+ unsigned depth, unsigned array_size,
+ unsigned usage, unsigned plane)
+{
+ unsigned height = tmpl->height;
+
+ memset(templ, 0, sizeof(*templ));
+ if (depth > 1)
+ templ->target = PIPE_TEXTURE_3D;
+ else if (array_size > 1)
+ templ->target = PIPE_TEXTURE_2D_ARRAY;
+ else
+ templ->target = PIPE_TEXTURE_2D;
+ templ->format = resource_format;
+ templ->width0 = tmpl->width;
+ templ->depth0 = depth;
+ templ->array_size = array_size;
+ templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET | tmpl->bind;
+ templ->usage = usage;
+
+ vl_video_buffer_adjust_size(&templ->width0, &height, plane,
+ tmpl->chroma_format, false);
+ templ->height0 = height;
+}
+