1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2013 Ilia Mirkin
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 <sys/types.h>
26bf215546Sopenharmony_ci#include <fcntl.h>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "util/format/u_format.h"
29bf215546Sopenharmony_ci#include "util/u_sampler.h"
30bf215546Sopenharmony_ci#include "vl/vl_zscan.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "nv50/nv84_video.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_cistatic int
35bf215546Sopenharmony_cinv84_copy_firmware(const char *path, void *dest, ssize_t len)
36bf215546Sopenharmony_ci{
37bf215546Sopenharmony_ci   int fd = open(path, O_RDONLY | O_CLOEXEC);
38bf215546Sopenharmony_ci   ssize_t r;
39bf215546Sopenharmony_ci   if (fd < 0) {
40bf215546Sopenharmony_ci      fprintf(stderr, "opening firmware file %s failed: %m\n", path);
41bf215546Sopenharmony_ci      return 1;
42bf215546Sopenharmony_ci   }
43bf215546Sopenharmony_ci   r = read(fd, dest, len);
44bf215546Sopenharmony_ci   close(fd);
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci   if (r != len) {
47bf215546Sopenharmony_ci      fprintf(stderr, "reading firmware file %s failed: %m\n", path);
48bf215546Sopenharmony_ci      return 1;
49bf215546Sopenharmony_ci   }
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   return 0;
52bf215546Sopenharmony_ci}
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_cistatic int
55bf215546Sopenharmony_cifilesize(const char *path)
56bf215546Sopenharmony_ci{
57bf215546Sopenharmony_ci   int ret;
58bf215546Sopenharmony_ci   struct stat statbuf;
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   ret = stat(path, &statbuf);
61bf215546Sopenharmony_ci   if (ret)
62bf215546Sopenharmony_ci      return ret;
63bf215546Sopenharmony_ci   return statbuf.st_size;
64bf215546Sopenharmony_ci}
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_cistatic struct nouveau_bo *
67bf215546Sopenharmony_cinv84_load_firmwares(struct nouveau_device *dev, struct nv84_decoder *dec,
68bf215546Sopenharmony_ci                    const char *fw1, const char *fw2)
69bf215546Sopenharmony_ci{
70bf215546Sopenharmony_ci   int ret, size1, size2 = 0;
71bf215546Sopenharmony_ci   struct nouveau_bo *fw;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci   size1 = filesize(fw1);
74bf215546Sopenharmony_ci   if (fw2)
75bf215546Sopenharmony_ci      size2 = filesize(fw2);
76bf215546Sopenharmony_ci   if (size1 < 0 || size2 < 0)
77bf215546Sopenharmony_ci      return NULL;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   dec->vp_fw2_offset = align(size1, 0x100);
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, dec->vp_fw2_offset + size2, NULL, &fw);
82bf215546Sopenharmony_ci   if (ret)
83bf215546Sopenharmony_ci      return NULL;
84bf215546Sopenharmony_ci   ret = nouveau_bo_map(fw, NOUVEAU_BO_WR, dec->client);
85bf215546Sopenharmony_ci   if (ret)
86bf215546Sopenharmony_ci      goto error;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   ret = nv84_copy_firmware(fw1, fw->map, size1);
89bf215546Sopenharmony_ci   if (fw2 && !ret)
90bf215546Sopenharmony_ci      ret = nv84_copy_firmware(fw2, fw->map + dec->vp_fw2_offset, size2);
91bf215546Sopenharmony_ci   munmap(fw->map, fw->size);
92bf215546Sopenharmony_ci   fw->map = NULL;
93bf215546Sopenharmony_ci   if (!ret)
94bf215546Sopenharmony_ci      return fw;
95bf215546Sopenharmony_cierror:
96bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &fw);
97bf215546Sopenharmony_ci   return NULL;
98bf215546Sopenharmony_ci}
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_cistatic struct nouveau_bo *
101bf215546Sopenharmony_cinv84_load_bsp_firmware(struct nouveau_device *dev, struct nv84_decoder *dec)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci   return nv84_load_firmwares(
104bf215546Sopenharmony_ci         dev, dec, "/lib/firmware/nouveau/nv84_bsp-h264", NULL);
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cistatic struct nouveau_bo *
108bf215546Sopenharmony_cinv84_load_vp_firmware(struct nouveau_device *dev, struct nv84_decoder *dec)
109bf215546Sopenharmony_ci{
110bf215546Sopenharmony_ci   return nv84_load_firmwares(
111bf215546Sopenharmony_ci         dev, dec,
112bf215546Sopenharmony_ci         "/lib/firmware/nouveau/nv84_vp-h264-1",
113bf215546Sopenharmony_ci         "/lib/firmware/nouveau/nv84_vp-h264-2");
114bf215546Sopenharmony_ci}
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_cistatic struct nouveau_bo *
117bf215546Sopenharmony_cinv84_load_vp_firmware_mpeg(struct nouveau_device *dev, struct nv84_decoder *dec)
118bf215546Sopenharmony_ci{
119bf215546Sopenharmony_ci   return nv84_load_firmwares(
120bf215546Sopenharmony_ci         dev, dec, "/lib/firmware/nouveau/nv84_vp-mpeg12", NULL);
121bf215546Sopenharmony_ci}
122bf215546Sopenharmony_ci
123bf215546Sopenharmony_cistatic void
124bf215546Sopenharmony_cinv84_decoder_decode_bitstream_h264(struct pipe_video_codec *decoder,
125bf215546Sopenharmony_ci                                   struct pipe_video_buffer *video_target,
126bf215546Sopenharmony_ci                                   struct pipe_picture_desc *picture,
127bf215546Sopenharmony_ci                                   unsigned num_buffers,
128bf215546Sopenharmony_ci                                   const void *const *data,
129bf215546Sopenharmony_ci                                   const unsigned *num_bytes)
130bf215546Sopenharmony_ci{
131bf215546Sopenharmony_ci   struct nv84_decoder *dec = (struct nv84_decoder *)decoder;
132bf215546Sopenharmony_ci   struct nv84_video_buffer *target = (struct nv84_video_buffer *)video_target;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   struct pipe_h264_picture_desc *desc = (struct pipe_h264_picture_desc *)picture;
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   assert(target->base.buffer_format == PIPE_FORMAT_NV12);
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   nv84_decoder_bsp(dec, desc, num_buffers, data, num_bytes, target);
139bf215546Sopenharmony_ci   nv84_decoder_vp_h264(dec, desc, target);
140bf215546Sopenharmony_ci}
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_cistatic void
143bf215546Sopenharmony_cinv84_decoder_flush(struct pipe_video_codec *decoder)
144bf215546Sopenharmony_ci{
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_cistatic void
148bf215546Sopenharmony_cinv84_decoder_begin_frame_h264(struct pipe_video_codec *decoder,
149bf215546Sopenharmony_ci                              struct pipe_video_buffer *target,
150bf215546Sopenharmony_ci                              struct pipe_picture_desc *picture)
151bf215546Sopenharmony_ci{
152bf215546Sopenharmony_ci}
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_cistatic void
155bf215546Sopenharmony_cinv84_decoder_end_frame_h264(struct pipe_video_codec *decoder,
156bf215546Sopenharmony_ci                            struct pipe_video_buffer *target,
157bf215546Sopenharmony_ci                            struct pipe_picture_desc *picture)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_cistatic void
162bf215546Sopenharmony_cinv84_decoder_decode_bitstream_mpeg12(struct pipe_video_codec *decoder,
163bf215546Sopenharmony_ci                                     struct pipe_video_buffer *video_target,
164bf215546Sopenharmony_ci                                     struct pipe_picture_desc *picture,
165bf215546Sopenharmony_ci                                     unsigned num_buffers,
166bf215546Sopenharmony_ci                                     const void *const *data,
167bf215546Sopenharmony_ci                                     const unsigned *num_bytes)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   struct nv84_decoder *dec = (struct nv84_decoder *)decoder;
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   assert(video_target->buffer_format == PIPE_FORMAT_NV12);
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   vl_mpg12_bs_decode(dec->mpeg12_bs,
174bf215546Sopenharmony_ci                      video_target,
175bf215546Sopenharmony_ci                      (struct pipe_mpeg12_picture_desc *)picture,
176bf215546Sopenharmony_ci                      num_buffers,
177bf215546Sopenharmony_ci                      data,
178bf215546Sopenharmony_ci                      num_bytes);
179bf215546Sopenharmony_ci}
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_cistatic void
182bf215546Sopenharmony_cinv84_decoder_begin_frame_mpeg12(struct pipe_video_codec *decoder,
183bf215546Sopenharmony_ci                              struct pipe_video_buffer *target,
184bf215546Sopenharmony_ci                              struct pipe_picture_desc *picture)
185bf215546Sopenharmony_ci{
186bf215546Sopenharmony_ci   struct nv84_decoder *dec = (struct nv84_decoder *)decoder;
187bf215546Sopenharmony_ci   struct pipe_mpeg12_picture_desc *desc = (struct pipe_mpeg12_picture_desc *)picture;
188bf215546Sopenharmony_ci   int i;
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci   nouveau_bo_wait(dec->mpeg12_bo, NOUVEAU_BO_RDWR, dec->client);
191bf215546Sopenharmony_ci   dec->mpeg12_mb_info = dec->mpeg12_bo->map + 0x100;
192bf215546Sopenharmony_ci   dec->mpeg12_data = dec->mpeg12_bo->map + 0x100 +
193bf215546Sopenharmony_ci      align(0x20 * mb(dec->base.width) * mb(dec->base.height), 0x100);
194bf215546Sopenharmony_ci   if (desc->intra_matrix) {
195bf215546Sopenharmony_ci      dec->zscan = desc->alternate_scan ? vl_zscan_alternate : vl_zscan_normal;
196bf215546Sopenharmony_ci      for (i = 0; i < 64; i++) {
197bf215546Sopenharmony_ci         dec->mpeg12_intra_matrix[i] = desc->intra_matrix[dec->zscan[i]];
198bf215546Sopenharmony_ci         dec->mpeg12_non_intra_matrix[i] = desc->non_intra_matrix[dec->zscan[i]];
199bf215546Sopenharmony_ci      }
200bf215546Sopenharmony_ci      dec->mpeg12_intra_matrix[0] = 1 << (7 - desc->intra_dc_precision);
201bf215546Sopenharmony_ci   }
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_cistatic void
205bf215546Sopenharmony_cinv84_decoder_end_frame_mpeg12(struct pipe_video_codec *decoder,
206bf215546Sopenharmony_ci                              struct pipe_video_buffer *target,
207bf215546Sopenharmony_ci                              struct pipe_picture_desc *picture)
208bf215546Sopenharmony_ci{
209bf215546Sopenharmony_ci   nv84_decoder_vp_mpeg12(
210bf215546Sopenharmony_ci         (struct nv84_decoder *)decoder,
211bf215546Sopenharmony_ci         (struct pipe_mpeg12_picture_desc *)picture,
212bf215546Sopenharmony_ci         (struct nv84_video_buffer *)target);
213bf215546Sopenharmony_ci}
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_cistatic void
216bf215546Sopenharmony_cinv84_decoder_decode_macroblock(struct pipe_video_codec *decoder,
217bf215546Sopenharmony_ci                               struct pipe_video_buffer *target,
218bf215546Sopenharmony_ci                               struct pipe_picture_desc *picture,
219bf215546Sopenharmony_ci                               const struct pipe_macroblock *macroblocks,
220bf215546Sopenharmony_ci                               unsigned num_macroblocks)
221bf215546Sopenharmony_ci{
222bf215546Sopenharmony_ci   const struct pipe_mpeg12_macroblock *mb = (const struct pipe_mpeg12_macroblock *)macroblocks;
223bf215546Sopenharmony_ci   for (int i = 0; i < num_macroblocks; i++, mb++) {
224bf215546Sopenharmony_ci      nv84_decoder_vp_mpeg12_mb(
225bf215546Sopenharmony_ci            (struct nv84_decoder *)decoder,
226bf215546Sopenharmony_ci            (struct pipe_mpeg12_picture_desc *)picture,
227bf215546Sopenharmony_ci            mb);
228bf215546Sopenharmony_ci   }
229bf215546Sopenharmony_ci}
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_cistatic void
232bf215546Sopenharmony_cinv84_decoder_destroy(struct pipe_video_codec *decoder)
233bf215546Sopenharmony_ci{
234bf215546Sopenharmony_ci   struct nv84_decoder *dec = (struct nv84_decoder *)decoder;
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->bsp_fw);
237bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->bsp_data);
238bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->vp_fw);
239bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->vp_data);
240bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->mbring);
241bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->vpring);
242bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->bitstream);
243bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->vp_params);
244bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &dec->fence);
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   nouveau_object_del(&dec->bsp);
247bf215546Sopenharmony_ci   nouveau_object_del(&dec->vp);
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   nouveau_bufctx_del(&dec->bsp_bufctx);
250bf215546Sopenharmony_ci   nouveau_pushbuf_del(&dec->bsp_pushbuf);
251bf215546Sopenharmony_ci   nouveau_object_del(&dec->bsp_channel);
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   nouveau_bufctx_del(&dec->vp_bufctx);
254bf215546Sopenharmony_ci   nouveau_pushbuf_del(&dec->vp_pushbuf);
255bf215546Sopenharmony_ci   nouveau_object_del(&dec->vp_channel);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   nouveau_client_del(&dec->client);
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   FREE(dec->mpeg12_bs);
260bf215546Sopenharmony_ci   FREE(dec);
261bf215546Sopenharmony_ci}
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_cistruct pipe_video_codec *
264bf215546Sopenharmony_cinv84_create_decoder(struct pipe_context *context,
265bf215546Sopenharmony_ci                    const struct pipe_video_codec *templ)
266bf215546Sopenharmony_ci{
267bf215546Sopenharmony_ci   struct nv50_context *nv50 = (struct nv50_context *)context;
268bf215546Sopenharmony_ci   struct nouveau_screen *screen = &nv50->screen->base;
269bf215546Sopenharmony_ci   struct nv84_decoder *dec;
270bf215546Sopenharmony_ci   struct nouveau_pushbuf *bsp_push, *vp_push;
271bf215546Sopenharmony_ci   struct nv50_surface surf;
272bf215546Sopenharmony_ci   struct nv50_miptree mip;
273bf215546Sopenharmony_ci   union pipe_color_union color;
274bf215546Sopenharmony_ci   struct nv04_fifo nv04_data = { .vram = 0xbeef0201, .gart = 0xbeef0202 };
275bf215546Sopenharmony_ci   int ret, i;
276bf215546Sopenharmony_ci   int is_h264 = u_reduce_video_profile(templ->profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC;
277bf215546Sopenharmony_ci   int is_mpeg12 = u_reduce_video_profile(templ->profile) == PIPE_VIDEO_FORMAT_MPEG12;
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   if (getenv("XVMC_VL"))
280bf215546Sopenharmony_ci      return vl_create_decoder(context, templ);
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci   if ((is_h264 && templ->entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) ||
283bf215546Sopenharmony_ci       (is_mpeg12 && templ->entrypoint > PIPE_VIDEO_ENTRYPOINT_IDCT)) {
284bf215546Sopenharmony_ci      debug_printf("%x\n", templ->entrypoint);
285bf215546Sopenharmony_ci      return NULL;
286bf215546Sopenharmony_ci   }
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci   if (!is_h264 && !is_mpeg12) {
289bf215546Sopenharmony_ci      debug_printf("invalid profile: %x\n", templ->profile);
290bf215546Sopenharmony_ci      return NULL;
291bf215546Sopenharmony_ci   }
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   dec = CALLOC_STRUCT(nv84_decoder);
294bf215546Sopenharmony_ci   if (!dec)
295bf215546Sopenharmony_ci      return NULL;
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   dec->base = *templ;
298bf215546Sopenharmony_ci   dec->base.context = context;
299bf215546Sopenharmony_ci   dec->base.destroy = nv84_decoder_destroy;
300bf215546Sopenharmony_ci   dec->base.flush = nv84_decoder_flush;
301bf215546Sopenharmony_ci   if (is_h264) {
302bf215546Sopenharmony_ci      dec->base.decode_bitstream = nv84_decoder_decode_bitstream_h264;
303bf215546Sopenharmony_ci      dec->base.begin_frame = nv84_decoder_begin_frame_h264;
304bf215546Sopenharmony_ci      dec->base.end_frame = nv84_decoder_end_frame_h264;
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci      dec->frame_mbs = mb(dec->base.width) * mb_half(dec->base.height) * 2;
307bf215546Sopenharmony_ci      dec->frame_size = dec->frame_mbs << 8;
308bf215546Sopenharmony_ci      dec->vpring_deblock = align(0x30 * dec->frame_mbs, 0x100);
309bf215546Sopenharmony_ci      dec->vpring_residual = 0x2000 + MAX2(0x32000, 0x600 * dec->frame_mbs);
310bf215546Sopenharmony_ci      dec->vpring_ctrl = MAX2(0x10000, align(0x1080 + 0x144 * dec->frame_mbs, 0x100));
311bf215546Sopenharmony_ci   } else if (is_mpeg12) {
312bf215546Sopenharmony_ci      dec->base.decode_macroblock = nv84_decoder_decode_macroblock;
313bf215546Sopenharmony_ci      dec->base.begin_frame = nv84_decoder_begin_frame_mpeg12;
314bf215546Sopenharmony_ci      dec->base.end_frame = nv84_decoder_end_frame_mpeg12;
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci      if (templ->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
317bf215546Sopenharmony_ci         dec->mpeg12_bs = CALLOC_STRUCT(vl_mpg12_bs);
318bf215546Sopenharmony_ci         if (!dec->mpeg12_bs)
319bf215546Sopenharmony_ci            goto fail;
320bf215546Sopenharmony_ci         vl_mpg12_bs_init(dec->mpeg12_bs, &dec->base);
321bf215546Sopenharmony_ci         dec->base.decode_bitstream = nv84_decoder_decode_bitstream_mpeg12;
322bf215546Sopenharmony_ci      }
323bf215546Sopenharmony_ci   } else {
324bf215546Sopenharmony_ci      goto fail;
325bf215546Sopenharmony_ci   }
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   ret = nouveau_client_new(screen->device, &dec->client);
328bf215546Sopenharmony_ci   if (ret)
329bf215546Sopenharmony_ci      goto fail;
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   if (is_h264) {
332bf215546Sopenharmony_ci      ret = nouveau_object_new(&screen->device->object, 0,
333bf215546Sopenharmony_ci                               NOUVEAU_FIFO_CHANNEL_CLASS,
334bf215546Sopenharmony_ci                               &nv04_data, sizeof(nv04_data), &dec->bsp_channel);
335bf215546Sopenharmony_ci      if (ret)
336bf215546Sopenharmony_ci         goto fail;
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci      ret = nouveau_pushbuf_new(dec->client, dec->bsp_channel, 4,
339bf215546Sopenharmony_ci                                32 * 1024, true, &dec->bsp_pushbuf);
340bf215546Sopenharmony_ci      if (ret)
341bf215546Sopenharmony_ci         goto fail;
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci      ret = nouveau_bufctx_new(dec->client, 1, &dec->bsp_bufctx);
344bf215546Sopenharmony_ci      if (ret)
345bf215546Sopenharmony_ci         goto fail;
346bf215546Sopenharmony_ci   }
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci   ret = nouveau_object_new(&screen->device->object, 0,
349bf215546Sopenharmony_ci                            NOUVEAU_FIFO_CHANNEL_CLASS,
350bf215546Sopenharmony_ci                            &nv04_data, sizeof(nv04_data), &dec->vp_channel);
351bf215546Sopenharmony_ci   if (ret)
352bf215546Sopenharmony_ci      goto fail;
353bf215546Sopenharmony_ci   ret = nouveau_pushbuf_new(dec->client, dec->vp_channel, 4,
354bf215546Sopenharmony_ci                             32 * 1024, true, &dec->vp_pushbuf);
355bf215546Sopenharmony_ci   if (ret)
356bf215546Sopenharmony_ci      goto fail;
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   ret = nouveau_bufctx_new(dec->client, 1, &dec->vp_bufctx);
359bf215546Sopenharmony_ci   if (ret)
360bf215546Sopenharmony_ci      goto fail;
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   bsp_push = dec->bsp_pushbuf;
363bf215546Sopenharmony_ci   vp_push = dec->vp_pushbuf;
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci   if (is_h264) {
366bf215546Sopenharmony_ci      dec->bsp_fw = nv84_load_bsp_firmware(screen->device, dec);
367bf215546Sopenharmony_ci      dec->vp_fw = nv84_load_vp_firmware(screen->device, dec);
368bf215546Sopenharmony_ci      if (!dec->bsp_fw || !dec->vp_fw)
369bf215546Sopenharmony_ci         goto fail;
370bf215546Sopenharmony_ci   }
371bf215546Sopenharmony_ci   if (is_mpeg12) {
372bf215546Sopenharmony_ci      dec->vp_fw = nv84_load_vp_firmware_mpeg(screen->device, dec);
373bf215546Sopenharmony_ci      if (!dec->vp_fw)
374bf215546Sopenharmony_ci         goto fail;
375bf215546Sopenharmony_ci   }
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   if (is_h264) {
378bf215546Sopenharmony_ci      ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,
379bf215546Sopenharmony_ci                           0, 0x40000, NULL, &dec->bsp_data);
380bf215546Sopenharmony_ci      if (ret)
381bf215546Sopenharmony_ci         goto fail;
382bf215546Sopenharmony_ci   }
383bf215546Sopenharmony_ci   ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,
384bf215546Sopenharmony_ci                        0, 0x40000, NULL, &dec->vp_data);
385bf215546Sopenharmony_ci   if (ret)
386bf215546Sopenharmony_ci      goto fail;
387bf215546Sopenharmony_ci   if (is_h264) {
388bf215546Sopenharmony_ci      ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,
389bf215546Sopenharmony_ci                           0,
390bf215546Sopenharmony_ci                           2 * (dec->vpring_deblock +
391bf215546Sopenharmony_ci                                dec->vpring_residual +
392bf215546Sopenharmony_ci                                dec->vpring_ctrl +
393bf215546Sopenharmony_ci                                0x1000),
394bf215546Sopenharmony_ci                           NULL, &dec->vpring);
395bf215546Sopenharmony_ci      if (ret)
396bf215546Sopenharmony_ci         goto fail;
397bf215546Sopenharmony_ci      ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP,
398bf215546Sopenharmony_ci                           0,
399bf215546Sopenharmony_ci                           (templ->max_references + 1) * dec->frame_mbs * 0x40 +
400bf215546Sopenharmony_ci                           dec->frame_size + 0x2000,
401bf215546Sopenharmony_ci                           NULL, &dec->mbring);
402bf215546Sopenharmony_ci      if (ret)
403bf215546Sopenharmony_ci         goto fail;
404bf215546Sopenharmony_ci      ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART,
405bf215546Sopenharmony_ci                           0, 2 * (0x700 + MAX2(0x40000, 0x800 + 0x180 * dec->frame_mbs)),
406bf215546Sopenharmony_ci                           NULL, &dec->bitstream);
407bf215546Sopenharmony_ci      if (ret)
408bf215546Sopenharmony_ci         goto fail;
409bf215546Sopenharmony_ci      ret = nouveau_bo_map(dec->bitstream, NOUVEAU_BO_WR, dec->client);
410bf215546Sopenharmony_ci      if (ret)
411bf215546Sopenharmony_ci         goto fail;
412bf215546Sopenharmony_ci      ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART,
413bf215546Sopenharmony_ci                           0, 0x2000, NULL, &dec->vp_params);
414bf215546Sopenharmony_ci      if (ret)
415bf215546Sopenharmony_ci         goto fail;
416bf215546Sopenharmony_ci      ret = nouveau_bo_map(dec->vp_params, NOUVEAU_BO_WR, dec->client);
417bf215546Sopenharmony_ci      if (ret)
418bf215546Sopenharmony_ci         goto fail;
419bf215546Sopenharmony_ci   }
420bf215546Sopenharmony_ci   if (is_mpeg12) {
421bf215546Sopenharmony_ci      ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART,
422bf215546Sopenharmony_ci                           0,
423bf215546Sopenharmony_ci                           align(0x20 * mb(templ->width) * mb(templ->height), 0x100) +
424bf215546Sopenharmony_ci                           (6 * 64 * 8) * mb(templ->width) * mb(templ->height) + 0x100,
425bf215546Sopenharmony_ci                           NULL, &dec->mpeg12_bo);
426bf215546Sopenharmony_ci      if (ret)
427bf215546Sopenharmony_ci         goto fail;
428bf215546Sopenharmony_ci      ret = nouveau_bo_map(dec->mpeg12_bo, NOUVEAU_BO_WR, dec->client);
429bf215546Sopenharmony_ci      if (ret)
430bf215546Sopenharmony_ci         goto fail;
431bf215546Sopenharmony_ci   }
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,
434bf215546Sopenharmony_ci                        0, 0x1000, NULL, &dec->fence);
435bf215546Sopenharmony_ci   if (ret)
436bf215546Sopenharmony_ci      goto fail;
437bf215546Sopenharmony_ci   ret = nouveau_bo_map(dec->fence, NOUVEAU_BO_WR, dec->client);
438bf215546Sopenharmony_ci   if (ret)
439bf215546Sopenharmony_ci      goto fail;
440bf215546Sopenharmony_ci   *(uint32_t *)dec->fence->map = 0;
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci   if (is_h264) {
443bf215546Sopenharmony_ci      nouveau_pushbuf_bufctx(bsp_push, dec->bsp_bufctx);
444bf215546Sopenharmony_ci      nouveau_bufctx_refn(dec->bsp_bufctx, 0,
445bf215546Sopenharmony_ci                          dec->bsp_fw, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
446bf215546Sopenharmony_ci      nouveau_bufctx_refn(dec->bsp_bufctx, 0,
447bf215546Sopenharmony_ci                          dec->bsp_data, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
448bf215546Sopenharmony_ci   }
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_ci   nouveau_pushbuf_bufctx(vp_push, dec->vp_bufctx);
451bf215546Sopenharmony_ci   nouveau_bufctx_refn(dec->vp_bufctx, 0, dec->vp_fw,
452bf215546Sopenharmony_ci                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
453bf215546Sopenharmony_ci   nouveau_bufctx_refn(dec->vp_bufctx, 0, dec->vp_data,
454bf215546Sopenharmony_ci                       NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   if (is_h264 && !ret)
457bf215546Sopenharmony_ci      ret = nouveau_object_new(dec->bsp_channel, 0xbeef74b0, 0x74b0,
458bf215546Sopenharmony_ci                               NULL, 0, &dec->bsp);
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   if (!ret)
461bf215546Sopenharmony_ci      ret = nouveau_object_new(dec->vp_channel, 0xbeef7476, 0x7476,
462bf215546Sopenharmony_ci                               NULL, 0, &dec->vp);
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci   if (ret)
465bf215546Sopenharmony_ci      goto fail;
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   if (is_h264) {
469bf215546Sopenharmony_ci      /* Zero out some parts of mbring/vpring. there's gotta be some cleaner way
470bf215546Sopenharmony_ci       * of doing this... perhaps makes sense to just copy the relevant logic
471bf215546Sopenharmony_ci       * here. */
472bf215546Sopenharmony_ci      color.f[0] = color.f[1] = color.f[2] = color.f[3] = 0;
473bf215546Sopenharmony_ci      surf.offset = dec->frame_size;
474bf215546Sopenharmony_ci      surf.width = 64;
475bf215546Sopenharmony_ci      surf.height = (templ->max_references + 1) * dec->frame_mbs / 4;
476bf215546Sopenharmony_ci      surf.depth = 1;
477bf215546Sopenharmony_ci      surf.base.format = PIPE_FORMAT_B8G8R8A8_UNORM;
478bf215546Sopenharmony_ci      surf.base.u.tex.level = 0;
479bf215546Sopenharmony_ci      surf.base.texture = &mip.base.base;
480bf215546Sopenharmony_ci      mip.level[0].tile_mode = 0;
481bf215546Sopenharmony_ci      mip.level[0].pitch = surf.width * 4;
482bf215546Sopenharmony_ci      mip.base.domain = NOUVEAU_BO_VRAM;
483bf215546Sopenharmony_ci      mip.base.bo = dec->mbring;
484bf215546Sopenharmony_ci      mip.base.address = dec->mbring->offset;
485bf215546Sopenharmony_ci      context->clear_render_target(context, &surf.base, &color, 0, 0, 64, 4760, false);
486bf215546Sopenharmony_ci      surf.offset = dec->vpring->size / 2 - 0x1000;
487bf215546Sopenharmony_ci      surf.width = 1024;
488bf215546Sopenharmony_ci      surf.height = 1;
489bf215546Sopenharmony_ci      mip.level[0].pitch = surf.width * 4;
490bf215546Sopenharmony_ci      mip.base.bo = dec->vpring;
491bf215546Sopenharmony_ci      mip.base.address = dec->vpring->offset;
492bf215546Sopenharmony_ci      context->clear_render_target(context, &surf.base, &color, 0, 0, 1024, 1, false);
493bf215546Sopenharmony_ci      surf.offset = dec->vpring->size - 0x1000;
494bf215546Sopenharmony_ci      context->clear_render_target(context, &surf.base, &color, 0, 0, 1024, 1, false);
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci      PUSH_SPACE(nv50->base.pushbuf, 5);
497bf215546Sopenharmony_ci      PUSH_REFN(nv50->base.pushbuf, dec->fence, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
498bf215546Sopenharmony_ci      /* The clear_render_target is done via 3D engine, so use it to write to a
499bf215546Sopenharmony_ci       * sempahore to indicate that it's done.
500bf215546Sopenharmony_ci       */
501bf215546Sopenharmony_ci      BEGIN_NV04(nv50->base.pushbuf, NV50_3D(QUERY_ADDRESS_HIGH), 4);
502bf215546Sopenharmony_ci      PUSH_DATAh(nv50->base.pushbuf, dec->fence->offset);
503bf215546Sopenharmony_ci      PUSH_DATA (nv50->base.pushbuf, dec->fence->offset);
504bf215546Sopenharmony_ci      PUSH_DATA (nv50->base.pushbuf, 1);
505bf215546Sopenharmony_ci      PUSH_DATA (nv50->base.pushbuf, 0xf010);
506bf215546Sopenharmony_ci      PUSH_KICK (nv50->base.pushbuf);
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci      PUSH_SPACE(bsp_push, 2 + 12 + 2 + 4 + 3);
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci      BEGIN_NV04(bsp_push, SUBC_BSP(NV01_SUBCHAN_OBJECT), 1);
511bf215546Sopenharmony_ci      PUSH_DATA (bsp_push, dec->bsp->handle);
512bf215546Sopenharmony_ci
513bf215546Sopenharmony_ci      BEGIN_NV04(bsp_push, SUBC_BSP(0x180), 11);
514bf215546Sopenharmony_ci      for (i = 0; i < 11; i++)
515bf215546Sopenharmony_ci         PUSH_DATA(bsp_push, nv04_data.vram);
516bf215546Sopenharmony_ci      BEGIN_NV04(bsp_push, SUBC_BSP(0x1b8), 1);
517bf215546Sopenharmony_ci      PUSH_DATA (bsp_push, nv04_data.vram);
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci      BEGIN_NV04(bsp_push, SUBC_BSP(0x600), 3);
520bf215546Sopenharmony_ci      PUSH_DATAh(bsp_push, dec->bsp_fw->offset);
521bf215546Sopenharmony_ci      PUSH_DATA (bsp_push, dec->bsp_fw->offset);
522bf215546Sopenharmony_ci      PUSH_DATA (bsp_push, dec->bsp_fw->size);
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci      BEGIN_NV04(bsp_push, SUBC_BSP(0x628), 2);
525bf215546Sopenharmony_ci      PUSH_DATA (bsp_push, dec->bsp_data->offset >> 8);
526bf215546Sopenharmony_ci      PUSH_DATA (bsp_push, dec->bsp_data->size);
527bf215546Sopenharmony_ci      PUSH_KICK (bsp_push);
528bf215546Sopenharmony_ci   }
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_ci   PUSH_SPACE(vp_push, 2 + 12 + 2 + 4 + 3);
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci   BEGIN_NV04(vp_push, SUBC_VP(NV01_SUBCHAN_OBJECT), 1);
533bf215546Sopenharmony_ci   PUSH_DATA (vp_push, dec->vp->handle);
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci   BEGIN_NV04(vp_push, SUBC_VP(0x180), 11);
536bf215546Sopenharmony_ci   for (i = 0; i < 11; i++)
537bf215546Sopenharmony_ci      PUSH_DATA(vp_push, nv04_data.vram);
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci   BEGIN_NV04(vp_push, SUBC_VP(0x1b8), 1);
540bf215546Sopenharmony_ci   PUSH_DATA (vp_push, nv04_data.vram);
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci   BEGIN_NV04(vp_push, SUBC_VP(0x600), 3);
543bf215546Sopenharmony_ci   PUSH_DATAh(vp_push, dec->vp_fw->offset);
544bf215546Sopenharmony_ci   PUSH_DATA (vp_push, dec->vp_fw->offset);
545bf215546Sopenharmony_ci   PUSH_DATA (vp_push, dec->vp_fw->size);
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci   BEGIN_NV04(vp_push, SUBC_VP(0x628), 2);
548bf215546Sopenharmony_ci   PUSH_DATA (vp_push, dec->vp_data->offset >> 8);
549bf215546Sopenharmony_ci   PUSH_DATA (vp_push, dec->vp_data->size);
550bf215546Sopenharmony_ci   PUSH_KICK (vp_push);
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_ci   return &dec->base;
553bf215546Sopenharmony_cifail:
554bf215546Sopenharmony_ci   nv84_decoder_destroy(&dec->base);
555bf215546Sopenharmony_ci   return NULL;
556bf215546Sopenharmony_ci}
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_cistatic struct pipe_sampler_view **
559bf215546Sopenharmony_cinv84_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
560bf215546Sopenharmony_ci{
561bf215546Sopenharmony_ci   struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;
562bf215546Sopenharmony_ci   return buf->sampler_view_planes;
563bf215546Sopenharmony_ci}
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_cistatic struct pipe_sampler_view **
566bf215546Sopenharmony_cinv84_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
567bf215546Sopenharmony_ci{
568bf215546Sopenharmony_ci   struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;
569bf215546Sopenharmony_ci   return buf->sampler_view_components;
570bf215546Sopenharmony_ci}
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_cistatic struct pipe_surface **
573bf215546Sopenharmony_cinv84_video_buffer_surfaces(struct pipe_video_buffer *buffer)
574bf215546Sopenharmony_ci{
575bf215546Sopenharmony_ci   struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;
576bf215546Sopenharmony_ci   return buf->surfaces;
577bf215546Sopenharmony_ci}
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_cistatic void
580bf215546Sopenharmony_cinv84_video_buffer_destroy(struct pipe_video_buffer *buffer)
581bf215546Sopenharmony_ci{
582bf215546Sopenharmony_ci   struct nv84_video_buffer *buf = (struct nv84_video_buffer *)buffer;
583bf215546Sopenharmony_ci   unsigned i;
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci   assert(buf);
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci   for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
588bf215546Sopenharmony_ci      pipe_resource_reference(&buf->resources[i], NULL);
589bf215546Sopenharmony_ci      pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
590bf215546Sopenharmony_ci      pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
591bf215546Sopenharmony_ci      pipe_surface_reference(&buf->surfaces[i * 2], NULL);
592bf215546Sopenharmony_ci      pipe_surface_reference(&buf->surfaces[i * 2 + 1], NULL);
593bf215546Sopenharmony_ci   }
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &buf->interlaced);
596bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &buf->full);
597bf215546Sopenharmony_ci
598bf215546Sopenharmony_ci   FREE(buffer);
599bf215546Sopenharmony_ci}
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_cistruct pipe_video_buffer *
602bf215546Sopenharmony_cinv84_video_buffer_create(struct pipe_context *pipe,
603bf215546Sopenharmony_ci                         const struct pipe_video_buffer *template)
604bf215546Sopenharmony_ci{
605bf215546Sopenharmony_ci   struct nv84_video_buffer *buffer;
606bf215546Sopenharmony_ci   struct pipe_resource templ;
607bf215546Sopenharmony_ci   unsigned i, j, component;
608bf215546Sopenharmony_ci   struct pipe_sampler_view sv_templ;
609bf215546Sopenharmony_ci   struct pipe_surface surf_templ;
610bf215546Sopenharmony_ci   struct nv50_miptree *mt0, *mt1;
611bf215546Sopenharmony_ci   struct nouveau_screen *screen = &((struct nv50_context *)pipe)->screen->base;
612bf215546Sopenharmony_ci   union nouveau_bo_config cfg;
613bf215546Sopenharmony_ci   unsigned bo_size;
614bf215546Sopenharmony_ci
615bf215546Sopenharmony_ci   if (getenv("XVMC_VL") || template->buffer_format != PIPE_FORMAT_NV12)
616bf215546Sopenharmony_ci      return vl_video_buffer_create(pipe, template);
617bf215546Sopenharmony_ci
618bf215546Sopenharmony_ci   if (!template->interlaced) {
619bf215546Sopenharmony_ci      debug_printf("Require interlaced video buffers\n");
620bf215546Sopenharmony_ci      return NULL;
621bf215546Sopenharmony_ci   }
622bf215546Sopenharmony_ci   if (pipe_format_to_chroma_format(template->buffer_format) != PIPE_VIDEO_CHROMA_FORMAT_420) {
623bf215546Sopenharmony_ci      debug_printf("Must use 4:2:0 format\n");
624bf215546Sopenharmony_ci      return NULL;
625bf215546Sopenharmony_ci   }
626bf215546Sopenharmony_ci
627bf215546Sopenharmony_ci   /*
628bf215546Sopenharmony_ci    * Note that there are always going to be exactly two planes, one for Y,
629bf215546Sopenharmony_ci    * and one for UV. These are also the resources. VP expects these to be
630bf215546Sopenharmony_ci    * adjacent, so they need to belong to the same BO.
631bf215546Sopenharmony_ci    */
632bf215546Sopenharmony_ci
633bf215546Sopenharmony_ci   buffer = CALLOC_STRUCT(nv84_video_buffer);
634bf215546Sopenharmony_ci   if (!buffer) return NULL;
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   buffer->mvidx = -1;
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   buffer->base.buffer_format = template->buffer_format;
639bf215546Sopenharmony_ci   buffer->base.context = pipe;
640bf215546Sopenharmony_ci   buffer->base.destroy = nv84_video_buffer_destroy;
641bf215546Sopenharmony_ci   buffer->base.width = template->width;
642bf215546Sopenharmony_ci   buffer->base.height = template->height;
643bf215546Sopenharmony_ci   buffer->base.get_sampler_view_planes = nv84_video_buffer_sampler_view_planes;
644bf215546Sopenharmony_ci   buffer->base.get_sampler_view_components = nv84_video_buffer_sampler_view_components;
645bf215546Sopenharmony_ci   buffer->base.get_surfaces = nv84_video_buffer_surfaces;
646bf215546Sopenharmony_ci   buffer->base.interlaced = true;
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci   memset(&templ, 0, sizeof(templ));
649bf215546Sopenharmony_ci   templ.target = PIPE_TEXTURE_2D_ARRAY;
650bf215546Sopenharmony_ci   templ.depth0 = 1;
651bf215546Sopenharmony_ci   templ.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
652bf215546Sopenharmony_ci   templ.format = PIPE_FORMAT_R8_UNORM;
653bf215546Sopenharmony_ci   templ.width0 = align(template->width, 2);
654bf215546Sopenharmony_ci   templ.height0 = align(template->height, 4) / 2;
655bf215546Sopenharmony_ci   templ.flags = NV50_RESOURCE_FLAG_VIDEO | NV50_RESOURCE_FLAG_NOALLOC;
656bf215546Sopenharmony_ci   templ.array_size = 2;
657bf215546Sopenharmony_ci
658bf215546Sopenharmony_ci   cfg.nv50.tile_mode = 0x20;
659bf215546Sopenharmony_ci   cfg.nv50.memtype = 0x70;
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci   buffer->resources[0] = pipe->screen->resource_create(pipe->screen, &templ);
662bf215546Sopenharmony_ci   if (!buffer->resources[0])
663bf215546Sopenharmony_ci      goto error;
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci   templ.format = PIPE_FORMAT_R8G8_UNORM;
666bf215546Sopenharmony_ci   templ.width0 /= 2;
667bf215546Sopenharmony_ci   templ.height0 /= 2;
668bf215546Sopenharmony_ci   buffer->resources[1] = pipe->screen->resource_create(pipe->screen, &templ);
669bf215546Sopenharmony_ci   if (!buffer->resources[1])
670bf215546Sopenharmony_ci      goto error;
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   mt0 = nv50_miptree(buffer->resources[0]);
673bf215546Sopenharmony_ci   mt1 = nv50_miptree(buffer->resources[1]);
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci   bo_size = mt0->total_size + mt1->total_size;
676bf215546Sopenharmony_ci   if (nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP, 0,
677bf215546Sopenharmony_ci                      bo_size, &cfg, &buffer->interlaced))
678bf215546Sopenharmony_ci      goto error;
679bf215546Sopenharmony_ci   /* XXX Change reference frame management so that this is only allocated in
680bf215546Sopenharmony_ci    * the decoder when necessary. */
681bf215546Sopenharmony_ci   if (nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM | NOUVEAU_BO_NOSNOOP, 0,
682bf215546Sopenharmony_ci                      bo_size, &cfg, &buffer->full))
683bf215546Sopenharmony_ci      goto error;
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_ci   nouveau_bo_ref(buffer->interlaced, &mt0->base.bo);
686bf215546Sopenharmony_ci   mt0->base.domain = NOUVEAU_BO_VRAM;
687bf215546Sopenharmony_ci   mt0->base.address = buffer->interlaced->offset;
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci   nouveau_bo_ref(buffer->interlaced, &mt1->base.bo);
690bf215546Sopenharmony_ci   mt1->base.domain = NOUVEAU_BO_VRAM;
691bf215546Sopenharmony_ci   mt1->base.offset = mt0->total_size;
692bf215546Sopenharmony_ci   mt1->base.address = buffer->interlaced->offset + mt0->total_size;
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci   memset(&sv_templ, 0, sizeof(sv_templ));
695bf215546Sopenharmony_ci   for (component = 0, i = 0; i < 2; ++i ) {
696bf215546Sopenharmony_ci      struct pipe_resource *res = buffer->resources[i];
697bf215546Sopenharmony_ci      unsigned nr_components = util_format_get_nr_components(res->format);
698bf215546Sopenharmony_ci
699bf215546Sopenharmony_ci      u_sampler_view_default_template(&sv_templ, res, res->format);
700bf215546Sopenharmony_ci      buffer->sampler_view_planes[i] =
701bf215546Sopenharmony_ci         pipe->create_sampler_view(pipe, res, &sv_templ);
702bf215546Sopenharmony_ci      if (!buffer->sampler_view_planes[i])
703bf215546Sopenharmony_ci         goto error;
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ci      for (j = 0; j < nr_components; ++j, ++component) {
706bf215546Sopenharmony_ci         sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b =
707bf215546Sopenharmony_ci            PIPE_SWIZZLE_X + j;
708bf215546Sopenharmony_ci         sv_templ.swizzle_a = PIPE_SWIZZLE_1;
709bf215546Sopenharmony_ci
710bf215546Sopenharmony_ci         buffer->sampler_view_components[component] =
711bf215546Sopenharmony_ci            pipe->create_sampler_view(pipe, res, &sv_templ);
712bf215546Sopenharmony_ci         if (!buffer->sampler_view_components[component])
713bf215546Sopenharmony_ci            goto error;
714bf215546Sopenharmony_ci      }
715bf215546Sopenharmony_ci   }
716bf215546Sopenharmony_ci
717bf215546Sopenharmony_ci   memset(&surf_templ, 0, sizeof(surf_templ));
718bf215546Sopenharmony_ci   for (j = 0; j < 2; ++j) {
719bf215546Sopenharmony_ci      surf_templ.format = buffer->resources[j]->format;
720bf215546Sopenharmony_ci      surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 0;
721bf215546Sopenharmony_ci      buffer->surfaces[j * 2] =
722bf215546Sopenharmony_ci         pipe->create_surface(pipe, buffer->resources[j], &surf_templ);
723bf215546Sopenharmony_ci      if (!buffer->surfaces[j * 2])
724bf215546Sopenharmony_ci         goto error;
725bf215546Sopenharmony_ci
726bf215546Sopenharmony_ci      surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = 1;
727bf215546Sopenharmony_ci      buffer->surfaces[j * 2 + 1] =
728bf215546Sopenharmony_ci         pipe->create_surface(pipe, buffer->resources[j], &surf_templ);
729bf215546Sopenharmony_ci      if (!buffer->surfaces[j * 2 + 1])
730bf215546Sopenharmony_ci         goto error;
731bf215546Sopenharmony_ci   }
732bf215546Sopenharmony_ci
733bf215546Sopenharmony_ci   return &buffer->base;
734bf215546Sopenharmony_ci
735bf215546Sopenharmony_cierror:
736bf215546Sopenharmony_ci   nv84_video_buffer_destroy(&buffer->base);
737bf215546Sopenharmony_ci   return NULL;
738bf215546Sopenharmony_ci}
739bf215546Sopenharmony_ci
740bf215546Sopenharmony_ci#define FIRMWARE_BSP_KERN  0x01
741bf215546Sopenharmony_ci#define FIRMWARE_VP_KERN   0x02
742bf215546Sopenharmony_ci#define FIRMWARE_BSP_H264  0x04
743bf215546Sopenharmony_ci#define FIRMWARE_VP_MPEG2  0x08
744bf215546Sopenharmony_ci#define FIRMWARE_VP_H264_1 0x10
745bf215546Sopenharmony_ci#define FIRMWARE_VP_H264_2 0x20
746bf215546Sopenharmony_ci#define FIRMWARE_PRESENT(val, fw) (val & FIRMWARE_ ## fw)
747bf215546Sopenharmony_ci
748bf215546Sopenharmony_cistatic int
749bf215546Sopenharmony_cifirmware_present(struct pipe_screen *pscreen, enum pipe_video_format codec)
750bf215546Sopenharmony_ci{
751bf215546Sopenharmony_ci   struct nouveau_screen *screen = nouveau_screen(pscreen);
752bf215546Sopenharmony_ci   struct nouveau_object *obj = NULL;
753bf215546Sopenharmony_ci   struct stat s;
754bf215546Sopenharmony_ci   int checked = screen->firmware_info.profiles_checked;
755bf215546Sopenharmony_ci   int present, ret;
756bf215546Sopenharmony_ci
757bf215546Sopenharmony_ci   if (!FIRMWARE_PRESENT(checked, VP_KERN)) {
758bf215546Sopenharmony_ci      ret = nouveau_object_new(screen->channel, 0, 0x7476, NULL, 0, &obj);
759bf215546Sopenharmony_ci      if (!ret)
760bf215546Sopenharmony_ci         screen->firmware_info.profiles_present |= FIRMWARE_VP_KERN;
761bf215546Sopenharmony_ci      nouveau_object_del(&obj);
762bf215546Sopenharmony_ci      screen->firmware_info.profiles_checked |= FIRMWARE_VP_KERN;
763bf215546Sopenharmony_ci   }
764bf215546Sopenharmony_ci
765bf215546Sopenharmony_ci   if (codec == PIPE_VIDEO_FORMAT_MPEG4_AVC) {
766bf215546Sopenharmony_ci      if (!FIRMWARE_PRESENT(checked, BSP_KERN)) {
767bf215546Sopenharmony_ci         ret = nouveau_object_new(screen->channel, 0, 0x74b0, NULL, 0, &obj);
768bf215546Sopenharmony_ci         if (!ret)
769bf215546Sopenharmony_ci            screen->firmware_info.profiles_present |= FIRMWARE_BSP_KERN;
770bf215546Sopenharmony_ci         nouveau_object_del(&obj);
771bf215546Sopenharmony_ci         screen->firmware_info.profiles_checked |= FIRMWARE_BSP_KERN;
772bf215546Sopenharmony_ci      }
773bf215546Sopenharmony_ci
774bf215546Sopenharmony_ci      if (!FIRMWARE_PRESENT(checked, VP_H264_1)) {
775bf215546Sopenharmony_ci         ret = stat("/lib/firmware/nouveau/nv84_vp-h264-1", &s);
776bf215546Sopenharmony_ci         if (!ret && s.st_size > 1000)
777bf215546Sopenharmony_ci            screen->firmware_info.profiles_present |= FIRMWARE_VP_H264_1;
778bf215546Sopenharmony_ci         screen->firmware_info.profiles_checked |= FIRMWARE_VP_H264_1;
779bf215546Sopenharmony_ci      }
780bf215546Sopenharmony_ci
781bf215546Sopenharmony_ci      /* should probably check the others, but assume that 1 means all */
782bf215546Sopenharmony_ci
783bf215546Sopenharmony_ci      present = screen->firmware_info.profiles_present;
784bf215546Sopenharmony_ci      return FIRMWARE_PRESENT(present, VP_KERN) &&
785bf215546Sopenharmony_ci         FIRMWARE_PRESENT(present, BSP_KERN) &&
786bf215546Sopenharmony_ci         FIRMWARE_PRESENT(present, VP_H264_1);
787bf215546Sopenharmony_ci   } else {
788bf215546Sopenharmony_ci      if (!FIRMWARE_PRESENT(checked, VP_MPEG2)) {
789bf215546Sopenharmony_ci         ret = stat("/lib/firmware/nouveau/nv84_vp-mpeg12", &s);
790bf215546Sopenharmony_ci         if (!ret && s.st_size > 1000)
791bf215546Sopenharmony_ci            screen->firmware_info.profiles_present |= FIRMWARE_VP_MPEG2;
792bf215546Sopenharmony_ci         screen->firmware_info.profiles_checked |= FIRMWARE_VP_MPEG2;
793bf215546Sopenharmony_ci      }
794bf215546Sopenharmony_ci      present = screen->firmware_info.profiles_present;
795bf215546Sopenharmony_ci      return FIRMWARE_PRESENT(present, VP_KERN) &&
796bf215546Sopenharmony_ci         FIRMWARE_PRESENT(present, VP_MPEG2);
797bf215546Sopenharmony_ci   }
798bf215546Sopenharmony_ci}
799bf215546Sopenharmony_ci
800bf215546Sopenharmony_ciint
801bf215546Sopenharmony_cinv84_screen_get_video_param(struct pipe_screen *pscreen,
802bf215546Sopenharmony_ci                            enum pipe_video_profile profile,
803bf215546Sopenharmony_ci                            enum pipe_video_entrypoint entrypoint,
804bf215546Sopenharmony_ci                            enum pipe_video_cap param)
805bf215546Sopenharmony_ci{
806bf215546Sopenharmony_ci   enum pipe_video_format codec;
807bf215546Sopenharmony_ci
808bf215546Sopenharmony_ci   switch (param) {
809bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_SUPPORTED:
810bf215546Sopenharmony_ci      codec = u_reduce_video_profile(profile);
811bf215546Sopenharmony_ci      return (codec == PIPE_VIDEO_FORMAT_MPEG4_AVC ||
812bf215546Sopenharmony_ci              codec == PIPE_VIDEO_FORMAT_MPEG12) &&
813bf215546Sopenharmony_ci         firmware_present(pscreen, codec);
814bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_NPOT_TEXTURES:
815bf215546Sopenharmony_ci      return 1;
816bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_WIDTH:
817bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_HEIGHT:
818bf215546Sopenharmony_ci      return 2048;
819bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_PREFERED_FORMAT:
820bf215546Sopenharmony_ci      return PIPE_FORMAT_NV12;
821bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
822bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
823bf215546Sopenharmony_ci      return true;
824bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
825bf215546Sopenharmony_ci      return false;
826bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_LEVEL:
827bf215546Sopenharmony_ci      switch (profile) {
828bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG1:
829bf215546Sopenharmony_ci         return 0;
830bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
831bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
832bf215546Sopenharmony_ci         return 3;
833bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
834bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
835bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
836bf215546Sopenharmony_ci         return 41;
837bf215546Sopenharmony_ci      default:
838bf215546Sopenharmony_ci         debug_printf("unknown video profile: %d\n", profile);
839bf215546Sopenharmony_ci         return 0;
840bf215546Sopenharmony_ci      }
841bf215546Sopenharmony_ci   case PIPE_VIDEO_CAP_MAX_MACROBLOCKS:
842bf215546Sopenharmony_ci      return 8192; /* vc-1 actually has 8190, but this is not supported */
843bf215546Sopenharmony_ci   default:
844bf215546Sopenharmony_ci      debug_printf("unknown video param: %d\n", param);
845bf215546Sopenharmony_ci      return 0;
846bf215546Sopenharmony_ci   }
847bf215546Sopenharmony_ci}
848bf215546Sopenharmony_ci
849bf215546Sopenharmony_cibool
850bf215546Sopenharmony_cinv84_screen_video_supported(struct pipe_screen *screen,
851bf215546Sopenharmony_ci                            enum pipe_format format,
852bf215546Sopenharmony_ci                            enum pipe_video_profile profile,
853bf215546Sopenharmony_ci                            enum pipe_video_entrypoint entrypoint)
854bf215546Sopenharmony_ci{
855bf215546Sopenharmony_ci   if (profile != PIPE_VIDEO_PROFILE_UNKNOWN)
856bf215546Sopenharmony_ci      return format == PIPE_FORMAT_NV12;
857bf215546Sopenharmony_ci
858bf215546Sopenharmony_ci   return vl_video_buffer_is_format_supported(screen, format, profile, entrypoint);
859bf215546Sopenharmony_ci}
860