xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/nouveau/nv50/nv98_video.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright 2011-2013 Maarten Lankhorst, Ilia Mirkin
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "nv50/nv98_video.h"
24 
25 #include "util/u_sampler.h"
26 #include "util/format/u_format.h"
27 
28 #include <nvif/class.h>
29 
30 static void
nv98_decoder_decode_bitstream(struct pipe_video_codec * decoder,struct pipe_video_buffer * video_target,struct pipe_picture_desc * picture,unsigned num_buffers,const void * const * data,const unsigned * num_bytes)31 nv98_decoder_decode_bitstream(struct pipe_video_codec *decoder,
32                               struct pipe_video_buffer *video_target,
33                               struct pipe_picture_desc *picture,
34                               unsigned num_buffers,
35                               const void *const *data,
36                               const unsigned *num_bytes)
37 {
38    struct nouveau_vp3_decoder *dec = (struct nouveau_vp3_decoder *)decoder;
39    struct nouveau_vp3_video_buffer *target = (struct nouveau_vp3_video_buffer *)video_target;
40    uint32_t comm_seq = ++dec->fence_seq;
41    union pipe_desc desc;
42 
43    unsigned vp_caps, is_ref;
44    ASSERTED unsigned ret; /* used in debug checks */
45    struct nouveau_vp3_video_buffer *refs[16] = {};
46 
47    desc.base = picture;
48 
49    assert(target->base.buffer_format == PIPE_FORMAT_NV12);
50 
51    ret = nv98_decoder_bsp(dec, desc, target, comm_seq,
52                           num_buffers, data, num_bytes,
53                           &vp_caps, &is_ref, refs);
54 
55    /* did we decode bitstream correctly? */
56    assert(ret == 2);
57 
58    nv98_decoder_vp(dec, desc, target, comm_seq, vp_caps, is_ref, refs);
59    nv98_decoder_ppp(dec, desc, target, comm_seq);
60 }
61 
62 static const struct nouveau_mclass
63 nv98_decoder_msvld[] = {
64    { G98_MSVLD, -1 },
65    { IGT21A_MSVLD, -1 },
66    { GT212_MSVLD, -1 },
67    {}
68 };
69 
70 static const struct nouveau_mclass
71 nv98_decoder_mspdec[] = {
72    { G98_MSPDEC, -1 },
73    { GT212_MSPDEC, -1 },
74    {}
75 };
76 
77 static const struct nouveau_mclass
78 nv98_decoder_msppp[] = {
79    { G98_MSPPP, -1 },
80    { GT212_MSPPP, -1 },
81    {}
82 };
83 
84 struct pipe_video_codec *
nv98_create_decoder(struct pipe_context * context,const struct pipe_video_codec * templ)85 nv98_create_decoder(struct pipe_context *context,
86                     const struct pipe_video_codec *templ)
87 {
88    struct nv50_context *nv50 = nv50_context(context);
89    struct nouveau_screen *screen = &nv50->screen->base;
90    struct nouveau_vp3_decoder *dec;
91    struct nouveau_pushbuf **push;
92    struct nv04_fifo nv04_data = {.vram = 0xbeef0201, .gart = 0xbeef0202};
93 
94    int ret, i;
95    uint32_t codec = 1, ppp_codec = 3;
96    uint32_t timeout;
97    u32 tmp_size = 0;
98 
99    if (templ->entrypoint != PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
100       debug_printf("%x\n", templ->entrypoint);
101       return NULL;
102    }
103 
104    dec = CALLOC_STRUCT(nouveau_vp3_decoder);
105    if (!dec)
106       return NULL;
107    dec->client = nv50->base.client;
108    dec->base = *templ;
109    nouveau_vp3_decoder_init_common(&dec->base);
110 
111    dec->bsp_idx = 5;
112    dec->vp_idx = 6;
113    dec->ppp_idx = 7;
114 
115    ret = nouveau_object_new(&screen->device->object, 0,
116                             NOUVEAU_FIFO_CHANNEL_CLASS,
117                             &nv04_data, sizeof(nv04_data), &dec->channel[0]);
118 
119    if (!ret)
120       ret = nouveau_pushbuf_create(screen, &nv50->base, nv50->base.client, dec->channel[0],
121                                    4, 32 * 1024, &dec->pushbuf[0]);
122 
123    for (i = 1; i < 3; ++i) {
124       dec->channel[i] = dec->channel[0];
125       dec->pushbuf[i] = dec->pushbuf[0];
126    }
127    push = dec->pushbuf;
128 
129    if (!ret) {
130       ret = nouveau_object_mclass(dec->channel[0], nv98_decoder_msvld);
131       if (ret >= 0) {
132          ret = nouveau_object_new(dec->channel[0], 0xbeef85b1,
133                                   nv98_decoder_msvld[ret].oclass, NULL, 0,
134                                   &dec->bsp);
135       }
136    }
137 
138    if (!ret) {
139       ret = nouveau_object_mclass(dec->channel[1], nv98_decoder_mspdec);
140       if (ret >= 0) {
141          ret = nouveau_object_new(dec->channel[1], 0xbeef85b2,
142                                   nv98_decoder_mspdec[ret].oclass, NULL, 0,
143                                   &dec->vp);
144       }
145    }
146 
147    if (!ret) {
148       ret = nouveau_object_mclass(dec->channel[2], nv98_decoder_msppp);
149       if (ret >= 0) {
150          ret = nouveau_object_new(dec->channel[2], 0xbeef85b3,
151                                   nv98_decoder_msppp[ret].oclass, NULL, 0,
152                                   &dec->ppp);
153       }
154    }
155 
156    if (ret)
157       goto fail;
158 
159    BEGIN_NV04(push[0], SUBC_BSP(NV01_SUBCHAN_OBJECT), 1);
160    PUSH_DATA (push[0], dec->bsp->handle);
161 
162    BEGIN_NV04(push[0], SUBC_BSP(0x180), 5);
163    for (i = 0; i < 5; i++)
164       PUSH_DATA (push[0], nv04_data.vram);
165 
166    BEGIN_NV04(push[1], SUBC_VP(NV01_SUBCHAN_OBJECT), 1);
167    PUSH_DATA (push[1], dec->vp->handle);
168 
169    BEGIN_NV04(push[1], SUBC_VP(0x180), 6);
170    for (i = 0; i < 6; i++)
171       PUSH_DATA (push[1], nv04_data.vram);
172 
173    BEGIN_NV04(push[2], SUBC_PPP(NV01_SUBCHAN_OBJECT), 1);
174    PUSH_DATA (push[2], dec->ppp->handle);
175 
176    BEGIN_NV04(push[2], SUBC_PPP(0x180), 5);
177    for (i = 0; i < 5; i++)
178       PUSH_DATA (push[2], nv04_data.vram);
179 
180    dec->base.context = context;
181    dec->base.decode_bitstream = nv98_decoder_decode_bitstream;
182 
183    for (i = 0; i < NOUVEAU_VP3_VIDEO_QDEPTH && !ret; ++i)
184       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,
185                            0, 1 << 20, NULL, &dec->bsp_bo[i]);
186    if (!ret)
187       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM,
188                            0x100, 4 << 20, NULL, &dec->inter_bo[0]);
189    if (!ret)
190       nouveau_bo_ref(dec->inter_bo[0], &dec->inter_bo[1]);
191    if (ret)
192       goto fail;
193 
194    switch (u_reduce_video_profile(templ->profile)) {
195    case PIPE_VIDEO_FORMAT_MPEG12: {
196       codec = 1;
197       assert(templ->max_references <= 2);
198       break;
199    }
200    case PIPE_VIDEO_FORMAT_MPEG4: {
201       codec = 4;
202       tmp_size = mb(templ->height)*16 * mb(templ->width)*16;
203       assert(templ->max_references <= 2);
204       break;
205    }
206    case PIPE_VIDEO_FORMAT_VC1: {
207       ppp_codec = codec = 2;
208       tmp_size = mb(templ->height)*16 * mb(templ->width)*16;
209       assert(templ->max_references <= 2);
210       break;
211    }
212    case PIPE_VIDEO_FORMAT_MPEG4_AVC: {
213       codec = 3;
214       dec->tmp_stride = 16 * mb_half(templ->width) * nouveau_vp3_video_align(templ->height) * 3 / 2;
215       tmp_size = dec->tmp_stride * (templ->max_references + 1);
216       assert(templ->max_references <= 16);
217       break;
218    }
219    default:
220       fprintf(stderr, "invalid codec\n");
221       goto fail;
222    }
223 
224    ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,
225                            0x4000, NULL, &dec->fw_bo);
226    if (ret)
227       goto fail;
228 
229    ret = nouveau_vp3_load_firmware(dec, templ->profile, screen->device->chipset);
230    if (ret)
231       goto fw_fail;
232 
233    if (codec != 3) {
234       ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,
235                            0x400, NULL, &dec->bitplane_bo);
236       if (ret)
237          goto fail;
238    }
239 
240    dec->ref_stride = mb(templ->width)*16 * (mb_half(templ->height)*32 + nouveau_vp3_video_align(templ->height)/2);
241    ret = nouveau_bo_new(screen->device, NOUVEAU_BO_VRAM, 0,
242                         dec->ref_stride * (templ->max_references+2) + tmp_size,
243                         NULL, &dec->ref_bo);
244    if (ret)
245       goto fail;
246 
247    timeout = 0;
248 
249    BEGIN_NV04(push[0], SUBC_BSP(0x200), 2);
250    PUSH_DATA (push[0], codec);
251    PUSH_DATA (push[0], timeout);
252 
253    BEGIN_NV04(push[1], SUBC_VP(0x200), 2);
254    PUSH_DATA (push[1], codec);
255    PUSH_DATA (push[1], timeout);
256 
257    BEGIN_NV04(push[2], SUBC_PPP(0x200), 2);
258    PUSH_DATA (push[2], ppp_codec);
259    PUSH_DATA (push[2], timeout);
260 
261    ++dec->fence_seq;
262 
263 #if NOUVEAU_VP3_DEBUG_FENCE
264    ret = nouveau_bo_new(screen->device, NOUVEAU_BO_GART|NOUVEAU_BO_MAP,
265                         0, 0x1000, NULL, &dec->fence_bo);
266    if (ret)
267       goto fail;
268 
269    BO_MAP(screen, dec->fence_bo, NOUVEAU_BO_RDWR, screen->client);
270    dec->fence_map = dec->fence_bo->map;
271    dec->fence_map[0] = dec->fence_map[4] = dec->fence_map[8] = 0;
272    dec->comm = (struct comm *)(dec->fence_map + (COMM_OFFSET/sizeof(*dec->fence_map)));
273 
274    /* So lets test if the fence is working? */
275    PUSH_SPACE_EX(push[0], 16, 1, 0);
276    PUSH_REF1 (push[0], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);
277    BEGIN_NV04(push[0], SUBC_BSP(0x240), 3);
278    PUSH_DATAh(push[0], dec->fence_bo->offset);
279    PUSH_DATA (push[0], dec->fence_bo->offset);
280    PUSH_DATA (push[0], dec->fence_seq);
281 
282    BEGIN_NV04(push[0], SUBC_BSP(0x304), 1);
283    PUSH_DATA (push[0], 0);
284    PUSH_KICK (push[0]);
285 
286    PUSH_SPACE_EX(push[1], 16, 1, 0);
287    PUSH_REF1 (push[1], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);
288    BEGIN_NV04(push[1], SUBC_VP(0x240), 3);
289    PUSH_DATAh(push[1], (dec->fence_bo->offset + 0x10));
290    PUSH_DATA (push[1], (dec->fence_bo->offset + 0x10));
291    PUSH_DATA (push[1], dec->fence_seq);
292 
293    BEGIN_NV04(push[1], SUBC_VP(0x304), 1);
294    PUSH_DATA (push[1], 0);
295    PUSH_KICK (push[1]);
296 
297    PUSH_SPACE_EX(push[2], 16, 1, 0);
298    PUSH_REF1 (push[2], dec->fence_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR);
299    BEGIN_NV04(push[2], SUBC_PPP(0x240), 3);
300    PUSH_DATAh(push[2], (dec->fence_bo->offset + 0x20));
301    PUSH_DATA (push[2], (dec->fence_bo->offset + 0x20));
302    PUSH_DATA (push[2], dec->fence_seq);
303 
304    BEGIN_NV04(push[2], SUBC_PPP(0x304), 1);
305    PUSH_DATA (push[2], 0);
306    PUSH_KICK (push[2]);
307 
308    usleep(100);
309    while (dec->fence_seq > dec->fence_map[0] ||
310           dec->fence_seq > dec->fence_map[4] ||
311           dec->fence_seq > dec->fence_map[8]) {
312       debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]);
313       usleep(100);
314    }
315    debug_printf("%u: %u %u %u\n", dec->fence_seq, dec->fence_map[0], dec->fence_map[4], dec->fence_map[8]);
316 #endif
317 
318    return &dec->base;
319 
320 fw_fail:
321    debug_printf("Cannot create decoder without firmware..\n");
322    dec->base.destroy(&dec->base);
323    return NULL;
324 
325 fail:
326    debug_printf("Creation failed: %s (%i)\n", strerror(-ret), ret);
327    dec->base.destroy(&dec->base);
328    return NULL;
329 }
330 
331 struct pipe_video_buffer *
nv98_video_buffer_create(struct pipe_context * pipe,const struct pipe_video_buffer * templat)332 nv98_video_buffer_create(struct pipe_context *pipe,
333                          const struct pipe_video_buffer *templat)
334 {
335    return nouveau_vp3_video_buffer_create(
336          pipe, templat, NV50_RESOURCE_FLAG_VIDEO);
337 }
338