1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2011-2013 Maarten Lankhorst
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
12bf215546Sopenharmony_ci * all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci#include <sys/mman.h>
24bf215546Sopenharmony_ci#include <sys/stat.h>
25bf215546Sopenharmony_ci#include <stdio.h>
26bf215546Sopenharmony_ci#include <fcntl.h>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <nvif/class.h>
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "nouveau_screen.h"
31bf215546Sopenharmony_ci#include "nouveau_context.h"
32bf215546Sopenharmony_ci#include "nouveau_vp3_video.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "util/u_video.h"
35bf215546Sopenharmony_ci#include "util/format/u_format.h"
36bf215546Sopenharmony_ci#include "util/u_sampler.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_cistatic struct pipe_sampler_view **
39bf215546Sopenharmony_cinouveau_vp3_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
40bf215546Sopenharmony_ci{
41bf215546Sopenharmony_ci   struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;
42bf215546Sopenharmony_ci   return buf->sampler_view_planes;
43bf215546Sopenharmony_ci}
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_cistatic struct pipe_sampler_view **
46bf215546Sopenharmony_cinouveau_vp3_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;
49bf215546Sopenharmony_ci   return buf->sampler_view_components;
50bf215546Sopenharmony_ci}
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_cistatic struct pipe_surface **
53bf215546Sopenharmony_cinouveau_vp3_video_buffer_surfaces(struct pipe_video_buffer *buffer)
54bf215546Sopenharmony_ci{
55bf215546Sopenharmony_ci   struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;
56bf215546Sopenharmony_ci   return buf->surfaces;
57bf215546Sopenharmony_ci}
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_cistatic void
60bf215546Sopenharmony_cinouveau_vp3_video_buffer_destroy(struct pipe_video_buffer *buffer)
61bf215546Sopenharmony_ci{
62bf215546Sopenharmony_ci   struct nouveau_vp3_video_buffer *buf = (struct nouveau_vp3_video_buffer *)buffer;
63bf215546Sopenharmony_ci   unsigned i;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   assert(buf);
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
68bf215546Sopenharmony_ci      pipe_resource_reference(&buf->resources[i], NULL);
69bf215546Sopenharmony_ci      pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
70bf215546Sopenharmony_ci      pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
71bf215546Sopenharmony_ci      pipe_surface_reference(&buf->surfaces[i * 2], NULL);
72bf215546Sopenharmony_ci      pipe_surface_reference(&buf->surfaces[i * 2 + 1], NULL);
73bf215546Sopenharmony_ci   }
74bf215546Sopenharmony_ci   FREE(buffer);
75bf215546Sopenharmony_ci}
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_cistruct pipe_video_buffer *
78bf215546Sopenharmony_cinouveau_vp3_video_buffer_create(struct pipe_context *pipe,
79bf215546Sopenharmony_ci                         const struct pipe_video_buffer *templat,
80bf215546Sopenharmony_ci                         int flags)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   struct nouveau_vp3_video_buffer *buffer;
83bf215546Sopenharmony_ci   struct pipe_resource templ;
84bf215546Sopenharmony_ci   unsigned i, j, component;
85bf215546Sopenharmony_ci   struct pipe_sampler_view sv_templ;
86bf215546Sopenharmony_ci   struct pipe_surface surf_templ;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   if (getenv("XVMC_VL") || templat->buffer_format != PIPE_FORMAT_NV12)
89bf215546Sopenharmony_ci      return vl_video_buffer_create(pipe, templat);
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   assert(templat->interlaced);
92bf215546Sopenharmony_ci   assert(pipe_format_to_chroma_format(templat->buffer_format) == PIPE_VIDEO_CHROMA_FORMAT_420);
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   buffer = CALLOC_STRUCT(nouveau_vp3_video_buffer);
95bf215546Sopenharmony_ci   if (!buffer)
96bf215546Sopenharmony_ci      return NULL;
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci   buffer->base.buffer_format = templat->buffer_format;
99bf215546Sopenharmony_ci   buffer->base.context = pipe;
100bf215546Sopenharmony_ci   buffer->base.destroy = nouveau_vp3_video_buffer_destroy;
101bf215546Sopenharmony_ci   buffer->base.width = templat->width;
102bf215546Sopenharmony_ci   buffer->base.height = templat->height;
103bf215546Sopenharmony_ci   buffer->base.get_sampler_view_planes = nouveau_vp3_video_buffer_sampler_view_planes;
104bf215546Sopenharmony_ci   buffer->base.get_sampler_view_components = nouveau_vp3_video_buffer_sampler_view_components;
105bf215546Sopenharmony_ci   buffer->base.get_surfaces = nouveau_vp3_video_buffer_surfaces;
106bf215546Sopenharmony_ci   buffer->base.interlaced = true;
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   memset(&templ, 0, sizeof(templ));
109bf215546Sopenharmony_ci   templ.target = PIPE_TEXTURE_2D_ARRAY;
110bf215546Sopenharmony_ci   templ.depth0 = 1;
111bf215546Sopenharmony_ci   templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
112bf215546Sopenharmony_ci   templ.format = PIPE_FORMAT_R8_UNORM;
113bf215546Sopenharmony_ci   templ.width0 = buffer->base.width;
114bf215546Sopenharmony_ci   templ.height0 = (buffer->base.height + 1)/2;
115bf215546Sopenharmony_ci   templ.flags = flags;
116bf215546Sopenharmony_ci   templ.array_size = 2;
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   buffer->resources[0] = pipe->screen->resource_create(pipe->screen, &templ);
119bf215546Sopenharmony_ci   if (!buffer->resources[0])
120bf215546Sopenharmony_ci      goto error;
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci   templ.format = PIPE_FORMAT_R8G8_UNORM;
123bf215546Sopenharmony_ci   buffer->num_planes = 2;
124bf215546Sopenharmony_ci   templ.width0 = (templ.width0 + 1) / 2;
125bf215546Sopenharmony_ci   templ.height0 = (templ.height0 + 1) / 2;
126bf215546Sopenharmony_ci   for (i = 1; i < buffer->num_planes; ++i) {
127bf215546Sopenharmony_ci      buffer->resources[i] = pipe->screen->resource_create(pipe->screen, &templ);
128bf215546Sopenharmony_ci      if (!buffer->resources[i])
129bf215546Sopenharmony_ci         goto error;
130bf215546Sopenharmony_ci   }
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   memset(&sv_templ, 0, sizeof(sv_templ));
133bf215546Sopenharmony_ci   for (component = 0, i = 0; i < buffer->num_planes; ++i ) {
134bf215546Sopenharmony_ci      struct pipe_resource *res = buffer->resources[i];
135bf215546Sopenharmony_ci      unsigned nr_components = util_format_get_nr_components(res->format);
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci      u_sampler_view_default_template(&sv_templ, res, res->format);
138bf215546Sopenharmony_ci      buffer->sampler_view_planes[i] = pipe->create_sampler_view(pipe, res, &sv_templ);
139bf215546Sopenharmony_ci      if (!buffer->sampler_view_planes[i])
140bf215546Sopenharmony_ci         goto error;
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci      for (j = 0; j < nr_components; ++j, ++component) {
143bf215546Sopenharmony_ci         sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_X + j;
144bf215546Sopenharmony_ci         sv_templ.swizzle_a = PIPE_SWIZZLE_1;
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci         buffer->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
147bf215546Sopenharmony_ci         if (!buffer->sampler_view_components[component])
148bf215546Sopenharmony_ci            goto error;
149bf215546Sopenharmony_ci      }
150bf215546Sopenharmony_ci  }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   memset(&surf_templ, 0, sizeof(surf_templ));
153bf215546Sopenharmony_ci   for (j = 0; j < buffer->num_planes; ++j) {
154bf215546Sopenharmony_ci      surf_templ.format = buffer->resources[j]->format;
155bf215546Sopenharmony_ci      surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 0;
156bf215546Sopenharmony_ci      buffer->surfaces[j * 2] = pipe->create_surface(pipe, buffer->resources[j], &surf_templ);
157bf215546Sopenharmony_ci      if (!buffer->surfaces[j * 2])
158bf215546Sopenharmony_ci         goto error;
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_ci      surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 1;
161bf215546Sopenharmony_ci      buffer->surfaces[j * 2 + 1] = pipe->create_surface(pipe, buffer->resources[j], &surf_templ);
162bf215546Sopenharmony_ci      if (!buffer->surfaces[j * 2 + 1])
163bf215546Sopenharmony_ci         goto error;
164bf215546Sopenharmony_ci   }
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   return &buffer->base;
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_cierror:
169bf215546Sopenharmony_ci   nouveau_vp3_video_buffer_destroy(&buffer->base);
170bf215546Sopenharmony_ci   return NULL;
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_cistatic void
174bf215546Sopenharmony_cinouveau_vp3_decoder_flush(struct pipe_video_codec *decoder)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci}
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_cistatic void
179bf215546Sopenharmony_cinouveau_vp3_decoder_begin_frame(struct pipe_video_codec *decoder,
180bf215546Sopenharmony_ci                                struct pipe_video_buffer *target,
181bf215546Sopenharmony_ci                                struct pipe_picture_desc *picture)
182bf215546Sopenharmony_ci{
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_cistatic void
186bf215546Sopenharmony_cinouveau_vp3_decoder_end_frame(struct pipe_video_codec *decoder,
187bf215546Sopenharmony_ci                              struct pipe_video_buffer *target,
188bf215546Sopenharmony_ci                              struct pipe_picture_desc *picture)
189bf215546Sopenharmony_ci{
190bf215546Sopenharmony_ci}
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_cistatic void
193bf215546Sopenharmony_cinouveau_vp3_decoder_destroy(struct pipe_video_codec *decoder)
194bf215546Sopenharmony_ci{
195bf215546Sopenharmony_ci   struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;
196bf215546Sopenharmony_ci   int i;
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->ref_bo);
199bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->bitplane_bo);
200bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->inter_bo[0]);
201bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->inter_bo[1]);
202bf215546Sopenharmony_ci#if NOUVEAU_VP3_DEBUG_FENCE
203bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->fence_bo);
204bf215546Sopenharmony_ci#endif
205bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->fw_bo);
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   for (i = 0; i < NOUVEAU_VP3_VIDEO_QDEPTH; ++i)
208bf215546Sopenharmony_ci      nouveau_bo_ref(NULL, &dec->bsp_bo[i]);
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   nouveau_object_del(&dec->bsp);
211bf215546Sopenharmony_ci   nouveau_object_del(&dec->vp);
212bf215546Sopenharmony_ci   nouveau_object_del(&dec->ppp);
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   if (dec->channel[0] != dec->channel[1]) {
215bf215546Sopenharmony_ci      for (i = 0; i < 3; ++i) {
216bf215546Sopenharmony_ci         nouveau_pushbuf_del(&dec->pushbuf[i]);
217bf215546Sopenharmony_ci         nouveau_object_del(&dec->channel[i]);
218bf215546Sopenharmony_ci      }
219bf215546Sopenharmony_ci   } else {
220bf215546Sopenharmony_ci      nouveau_pushbuf_del(dec->pushbuf);
221bf215546Sopenharmony_ci      nouveau_object_del(dec->channel);
222bf215546Sopenharmony_ci   }
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci   FREE(dec);
225bf215546Sopenharmony_ci}
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_civoid
228bf215546Sopenharmony_cinouveau_vp3_decoder_init_common(struct pipe_video_codec *dec)
229bf215546Sopenharmony_ci{
230bf215546Sopenharmony_ci   dec->destroy = nouveau_vp3_decoder_destroy;
231bf215546Sopenharmony_ci   dec->flush = nouveau_vp3_decoder_flush;
232bf215546Sopenharmony_ci   dec->begin_frame = nouveau_vp3_decoder_begin_frame;
233bf215546Sopenharmony_ci   dec->end_frame = nouveau_vp3_decoder_end_frame;
234bf215546Sopenharmony_ci}
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_cistatic void vp3_getpath(enum pipe_video_profile profile, char *path)
237bf215546Sopenharmony_ci{
238bf215546Sopenharmony_ci   switch (u_reduce_video_profile(profile)) {
239bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG12: {
240bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-vp3-mpeg12-0");
241bf215546Sopenharmony_ci         break;
242bf215546Sopenharmony_ci      }
243bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_VC1: {
244bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-vp3-vc1-0");
245bf215546Sopenharmony_ci         break;
246bf215546Sopenharmony_ci      }
247bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
248bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-vp3-h264-0");
249bf215546Sopenharmony_ci         break;
250bf215546Sopenharmony_ci      }
251bf215546Sopenharmony_ci      default: assert(0);
252bf215546Sopenharmony_ci   }
253bf215546Sopenharmony_ci}
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_cistatic void vp4_getpath(enum pipe_video_profile profile, char *path)
256bf215546Sopenharmony_ci{
257bf215546Sopenharmony_ci   switch (u_reduce_video_profile(profile)) {
258bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG12: {
259bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-mpeg12-0");
260bf215546Sopenharmony_ci         break;
261bf215546Sopenharmony_ci      }
262bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4: {
263bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-mpeg4-0");
264bf215546Sopenharmony_ci         break;
265bf215546Sopenharmony_ci      }
266bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_VC1: {
267bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-vc1-0");
268bf215546Sopenharmony_ci         break;
269bf215546Sopenharmony_ci      }
270bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
271bf215546Sopenharmony_ci         sprintf(path, "/lib/firmware/nouveau/vuc-h264-0");
272bf215546Sopenharmony_ci         break;
273bf215546Sopenharmony_ci      }
274bf215546Sopenharmony_ci      default: assert(0);
275bf215546Sopenharmony_ci   }
276bf215546Sopenharmony_ci}
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ciint
279bf215546Sopenharmony_cinouveau_vp3_load_firmware(struct nouveau_vp3_decoder *dec,
280bf215546Sopenharmony_ci                          enum pipe_video_profile profile,
281bf215546Sopenharmony_ci                          unsigned chipset)
282bf215546Sopenharmony_ci{
283bf215546Sopenharmony_ci   int fd;
284bf215546Sopenharmony_ci   char path[PATH_MAX];
285bf215546Sopenharmony_ci   ssize_t r;
286bf215546Sopenharmony_ci   uint32_t *end, endval;
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci   if (chipset >= 0xa3 && chipset != 0xaa && chipset != 0xac)
289bf215546Sopenharmony_ci      vp4_getpath(profile, path);
290bf215546Sopenharmony_ci   else
291bf215546Sopenharmony_ci      vp3_getpath(profile, path);
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   if (nouveau_bo_map(dec->fw_bo, NOUVEAU_BO_WR, dec->client))
294bf215546Sopenharmony_ci      return 1;
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   fd = open(path, O_RDONLY | O_CLOEXEC);
297bf215546Sopenharmony_ci   if (fd < 0) {
298bf215546Sopenharmony_ci      fprintf(stderr, "opening firmware file %s failed: %m\n", path);
299bf215546Sopenharmony_ci      return 1;
300bf215546Sopenharmony_ci   }
301bf215546Sopenharmony_ci   r = read(fd, dec->fw_bo->map, 0x4000);
302bf215546Sopenharmony_ci   close(fd);
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   if (r < 0) {
305bf215546Sopenharmony_ci      fprintf(stderr, "reading firmware file %s failed: %m\n", path);
306bf215546Sopenharmony_ci      return 1;
307bf215546Sopenharmony_ci   }
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   if (r == 0x4000) {
310bf215546Sopenharmony_ci      fprintf(stderr, "firmware file %s too large!\n", path);
311bf215546Sopenharmony_ci      return 1;
312bf215546Sopenharmony_ci   }
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   if (r & 0xff) {
315bf215546Sopenharmony_ci      fprintf(stderr, "firmware file %s wrong size!\n", path);
316bf215546Sopenharmony_ci      return 1;
317bf215546Sopenharmony_ci   }
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   end = dec->fw_bo->map + r - 4;
320bf215546Sopenharmony_ci   endval = *end;
321bf215546Sopenharmony_ci   while (endval == *end)
322bf215546Sopenharmony_ci      end--;
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   r = (intptr_t)end - (intptr_t)dec->fw_bo->map + 4;
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   switch (u_reduce_video_profile(profile)) {
327bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG12: {
328bf215546Sopenharmony_ci         assert((r & 0xff) == 0xe0);
329bf215546Sopenharmony_ci         dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
330bf215546Sopenharmony_ci         break;
331bf215546Sopenharmony_ci      }
332bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4: {
333bf215546Sopenharmony_ci         assert((r & 0xff) == 0xe0);
334bf215546Sopenharmony_ci         dec->fw_sizes = (0x2e0<<16) | (r - 0x2e0);
335bf215546Sopenharmony_ci         break;
336bf215546Sopenharmony_ci      }
337bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_VC1: {
338bf215546Sopenharmony_ci         assert((r & 0xff) == 0xac);
339bf215546Sopenharmony_ci         dec->fw_sizes = (0x3ac<<16) | (r - 0x3ac);
340bf215546Sopenharmony_ci         break;
341bf215546Sopenharmony_ci      }
342bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
343bf215546Sopenharmony_ci         assert((r & 0xff) == 0x70);
344bf215546Sopenharmony_ci         dec->fw_sizes = (0x370<<16) | (r - 0x370);
345bf215546Sopenharmony_ci         break;
346bf215546Sopenharmony_ci      }
347bf215546Sopenharmony_ci      default:
348bf215546Sopenharmony_ci         return 1;
349bf215546Sopenharmony_ci   }
350bf215546Sopenharmony_ci   munmap(dec->fw_bo->map, dec->fw_bo->size);
351bf215546Sopenharmony_ci   dec->fw_bo->map = NULL;
352bf215546Sopenharmony_ci   return 0;
353bf215546Sopenharmony_ci}
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_cistatic const struct nouveau_mclass
356bf215546Sopenharmony_cinouveau_decoder_msvld[] = {
357bf215546Sopenharmony_ci   { G98_MSVLD, -1 },
358bf215546Sopenharmony_ci   { IGT21A_MSVLD, -1 },
359bf215546Sopenharmony_ci   { GT212_MSVLD, -1 },
360bf215546Sopenharmony_ci   { GF100_MSVLD, -1 },
361bf215546Sopenharmony_ci   { GK104_MSVLD, -1 },
362bf215546Sopenharmony_ci   {}
363bf215546Sopenharmony_ci};
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_cistatic int
366bf215546Sopenharmony_cifirmware_present(struct pipe_screen *pscreen, enum pipe_video_profile profile)
367bf215546Sopenharmony_ci{
368bf215546Sopenharmony_ci   struct nouveau_screen *screen = nouveau_screen(pscreen);
369bf215546Sopenharmony_ci   int chipset = screen->device->chipset;
370bf215546Sopenharmony_ci   int vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;
371bf215546Sopenharmony_ci   int vp5 = chipset >= 0xd0;
372bf215546Sopenharmony_ci   int ret;
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   /* For all chipsets, try to create a BSP objects. Assume that if firmware
375bf215546Sopenharmony_ci    * is present for it, firmware is also present for VP/PPP */
376bf215546Sopenharmony_ci   if (!(screen->firmware_info.profiles_checked & 1)) {
377bf215546Sopenharmony_ci      struct nouveau_object *channel = NULL, *bsp = NULL;
378bf215546Sopenharmony_ci      struct nv04_fifo nv04_data = {.vram = 0xbeef0201, .gart = 0xbeef0202};
379bf215546Sopenharmony_ci      struct nvc0_fifo nvc0_args = {};
380bf215546Sopenharmony_ci      struct nve0_fifo nve0_args = {.engine = NVE0_FIFO_ENGINE_BSP};
381bf215546Sopenharmony_ci      void *data = NULL;
382bf215546Sopenharmony_ci      int size;
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci      if (chipset < 0xc0) {
385bf215546Sopenharmony_ci         data = &nv04_data;
386bf215546Sopenharmony_ci         size = sizeof(nv04_data);
387bf215546Sopenharmony_ci      } else if (chipset < 0xe0) {
388bf215546Sopenharmony_ci         data = &nvc0_args;
389bf215546Sopenharmony_ci         size = sizeof(nvc0_args);
390bf215546Sopenharmony_ci      } else {
391bf215546Sopenharmony_ci         data = &nve0_args;
392bf215546Sopenharmony_ci         size = sizeof(nve0_args);
393bf215546Sopenharmony_ci      }
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci      /* kepler must have its own channel, so just do this for everyone */
396bf215546Sopenharmony_ci      nouveau_object_new(&screen->device->object, 0,
397bf215546Sopenharmony_ci                         NOUVEAU_FIFO_CHANNEL_CLASS,
398bf215546Sopenharmony_ci                         data, size, &channel);
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci      if (channel) {
401bf215546Sopenharmony_ci         ret = nouveau_object_mclass(channel, nouveau_decoder_msvld);
402bf215546Sopenharmony_ci         if (ret >= 0)
403bf215546Sopenharmony_ci            nouveau_object_new(channel, 0, nouveau_decoder_msvld[ret].oclass,
404bf215546Sopenharmony_ci                               NULL, 0, &bsp);
405bf215546Sopenharmony_ci         if (bsp)
406bf215546Sopenharmony_ci            screen->firmware_info.profiles_present |= 1;
407bf215546Sopenharmony_ci         nouveau_object_del(&bsp);
408bf215546Sopenharmony_ci         nouveau_object_del(&channel);
409bf215546Sopenharmony_ci      }
410bf215546Sopenharmony_ci      screen->firmware_info.profiles_checked |= 1;
411bf215546Sopenharmony_ci   }
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci   if (!(screen->firmware_info.profiles_present & 1))
414bf215546Sopenharmony_ci      return 0;
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   /* For vp3/vp4 chipsets, make sure that the relevant firmware is present */
417bf215546Sopenharmony_ci   if (!vp5 && !(screen->firmware_info.profiles_checked & (1 << profile))) {
418bf215546Sopenharmony_ci      char path[PATH_MAX];
419bf215546Sopenharmony_ci      struct stat s;
420bf215546Sopenharmony_ci      if (vp3)
421bf215546Sopenharmony_ci         vp3_getpath(profile, path);
422bf215546Sopenharmony_ci      else
423bf215546Sopenharmony_ci         vp4_getpath(profile, path);
424bf215546Sopenharmony_ci      ret = stat(path, &s);
425bf215546Sopenharmony_ci      if (!ret && s.st_size > 1000)
426bf215546Sopenharmony_ci         screen->firmware_info.profiles_present |= (1 << profile);
427bf215546Sopenharmony_ci      screen->firmware_info.profiles_checked |= (1 << profile);
428bf215546Sopenharmony_ci   }
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   return vp5 || (screen->firmware_info.profiles_present & (1 << profile));
431bf215546Sopenharmony_ci}
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ciint
434bf215546Sopenharmony_cinouveau_vp3_screen_get_video_param(struct pipe_screen *pscreen,
435bf215546Sopenharmony_ci                                   enum pipe_video_profile profile,
436bf215546Sopenharmony_ci                                   enum pipe_video_entrypoint entrypoint,
437bf215546Sopenharmony_ci                                   enum pipe_video_cap param)
438bf215546Sopenharmony_ci{
439bf215546Sopenharmony_ci   const int chipset = nouveau_screen(pscreen)->device->chipset;
440bf215546Sopenharmony_ci   /* Feature Set B = vp3, C = vp4, D = vp5 */
441bf215546Sopenharmony_ci   const bool vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;
442bf215546Sopenharmony_ci   const bool vp5 = chipset >= 0xd0;
443bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(profile);
444bf215546Sopenharmony_ci   switch (param) {
445bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_SUPPORTED:
446bf215546Sopenharmony_ci      /* VP3 does not support MPEG4, VP4+ do. */
447bf215546Sopenharmony_ci      return entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM &&
448bf215546Sopenharmony_ci         profile >= PIPE_VIDEO_PROFILE_MPEG1 &&
449bf215546Sopenharmony_ci         profile < PIPE_VIDEO_PROFILE_HEVC_MAIN &&
450bf215546Sopenharmony_ci         (!vp3 || codec != PIPE_VIDEO_FORMAT_MPEG4) &&
451bf215546Sopenharmony_ci         firmware_present(pscreen, profile);
452bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_NPOT_TEXTURES:
453bf215546Sopenharmony_ci      return 1;
454bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_WIDTH:
455bf215546Sopenharmony_ci      switch (codec) {
456bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG12:
457bf215546Sopenharmony_ci         return vp5 ? 4032 : 2048;
458bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4:
459bf215546Sopenharmony_ci         return 2048;
460bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_VC1:
461bf215546Sopenharmony_ci         return 2048;
462bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
463bf215546Sopenharmony_ci         if (vp3)
464bf215546Sopenharmony_ci            return 2032;
465bf215546Sopenharmony_ci         if (vp5)
466bf215546Sopenharmony_ci            return 4032;
467bf215546Sopenharmony_ci         return 2048; /* vp4 */
468bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_UNKNOWN:
469bf215546Sopenharmony_ci         return vp5 ? 4032 : 2048;
470bf215546Sopenharmony_ci      default:
471bf215546Sopenharmony_ci         debug_printf("unknown video codec: %d\n", codec);
472bf215546Sopenharmony_ci         return 0;
473bf215546Sopenharmony_ci      }
474bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_HEIGHT:
475bf215546Sopenharmony_ci      switch (codec) {
476bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG12:
477bf215546Sopenharmony_ci         return vp5 ? 4048 : 2048;
478bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4:
479bf215546Sopenharmony_ci         return 2048;
480bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_VC1:
481bf215546Sopenharmony_ci         return 2048;
482bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
483bf215546Sopenharmony_ci         if (vp3)
484bf215546Sopenharmony_ci            return 2048;
485bf215546Sopenharmony_ci         if (vp5)
486bf215546Sopenharmony_ci            return 4080;
487bf215546Sopenharmony_ci         return 2048; /* vp4 */
488bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_UNKNOWN:
489bf215546Sopenharmony_ci         return vp5 ? 4080 : 2048;
490bf215546Sopenharmony_ci      default:
491bf215546Sopenharmony_ci         debug_printf("unknown video codec: %d\n", codec);
492bf215546Sopenharmony_ci         return 0;
493bf215546Sopenharmony_ci      }
494bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_PREFERED_FORMAT:
495bf215546Sopenharmony_ci      return PIPE_FORMAT_NV12;
496bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
497bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
498bf215546Sopenharmony_ci      return true;
499bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
500bf215546Sopenharmony_ci      return false;
501bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_LEVEL:
502bf215546Sopenharmony_ci      switch (profile) {
503bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG1:
504bf215546Sopenharmony_ci         return 0;
505bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
506bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
507bf215546Sopenharmony_ci         return 3;
508bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
509bf215546Sopenharmony_ci         return 3;
510bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
511bf215546Sopenharmony_ci         return 5;
512bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
513bf215546Sopenharmony_ci         return 1;
514bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_VC1_MAIN:
515bf215546Sopenharmony_ci         return 2;
516bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
517bf215546Sopenharmony_ci         return 4;
518bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
519bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
520bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
521bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
522bf215546Sopenharmony_ci         return 41;
523bf215546Sopenharmony_ci      default:
524bf215546Sopenharmony_ci         debug_printf("unknown video profile: %d\n", profile);
525bf215546Sopenharmony_ci         return 0;
526bf215546Sopenharmony_ci      }
527bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_MACROBLOCKS:
528bf215546Sopenharmony_ci      switch (codec) {
529bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG12:
530bf215546Sopenharmony_ci         return vp5 ? 65536 : 8192;
531bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4:
532bf215546Sopenharmony_ci         return 8192;
533bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_VC1:
534bf215546Sopenharmony_ci         return 8190;
535bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
536bf215546Sopenharmony_ci         if (vp3)
537bf215546Sopenharmony_ci            return 8190;
538bf215546Sopenharmony_ci         if (vp5)
539bf215546Sopenharmony_ci            return 65536;
540bf215546Sopenharmony_ci         return 8192; /* vp4 */
541bf215546Sopenharmony_ci      default:
542bf215546Sopenharmony_ci         debug_printf("unknown video codec: %d\n", codec);
543bf215546Sopenharmony_ci         return 0;
544bf215546Sopenharmony_ci      }
545bf215546Sopenharmony_ci   default:
546bf215546Sopenharmony_ci      debug_printf("unknown video param: %d\n", param);
547bf215546Sopenharmony_ci      return 0;
548bf215546Sopenharmony_ci   }
549bf215546Sopenharmony_ci}
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_cibool
552bf215546Sopenharmony_cinouveau_vp3_screen_video_supported(struct pipe_screen *screen,
553bf215546Sopenharmony_ci                                   enum pipe_format format,
554bf215546Sopenharmony_ci                                   enum pipe_video_profile profile,
555bf215546Sopenharmony_ci                                   enum pipe_video_entrypoint entrypoint)
556bf215546Sopenharmony_ci{
557bf215546Sopenharmony_ci   if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)
558bf215546Sopenharmony_ci      return format == PIPE_FORMAT_NV12;
559bf215546Sopenharmony_ci
560bf215546Sopenharmony_ci   return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);
561bf215546Sopenharmony_ci}
562