2 * Copyright 2011-2013 Maarten Lankhorst, Ilia Mirkin
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
23 #include "nv50/nv98_video.h"
25 #include "util/u_sampler.h"
26 #include "util/u_format.h"
28 #include <nvif/class.h>
31 nv98_decoder_decode_bitstream(struct pipe_video_codec
*decoder
,
32 struct pipe_video_buffer
*video_target
,
33 struct pipe_picture_desc
*picture
,
35 const void *const *data
,
36 const unsigned *num_bytes
)
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
;
43 unsigned vp_caps
, is_ref
;
44 MAYBE_UNUSED
unsigned ret
; /* used in debug checks */
45 struct nouveau_vp3_video_buffer
*refs
[16] = {};
49 assert(target
->base
.buffer_format
== PIPE_FORMAT_NV12
);
51 ret
= nv98_decoder_bsp(dec
, desc
, target
, comm_seq
,
52 num_buffers
, data
, num_bytes
,
53 &vp_caps
, &is_ref
, refs
);
55 /* did we decode bitstream correctly? */
58 nv98_decoder_vp(dec
, desc
, target
, comm_seq
, vp_caps
, is_ref
, refs
);
59 nv98_decoder_ppp(dec
, desc
, target
, comm_seq
);
62 static const struct nouveau_mclass
63 nv98_decoder_msvld
[] = {
70 static const struct nouveau_mclass
71 nv98_decoder_mspdec
[] = {
77 static const struct nouveau_mclass
78 nv98_decoder_msppp
[] = {
84 struct pipe_video_codec
*
85 nv98_create_decoder(struct pipe_context
*context
,
86 const struct pipe_video_codec
*templ
)
88 struct nouveau_screen
*screen
= &((struct nv50_context
*)context
)->screen
->base
;
89 struct nouveau_vp3_decoder
*dec
;
90 struct nouveau_pushbuf
**push
;
91 struct nv04_fifo nv04_data
= {.vram
= 0xbeef0201, .gart
= 0xbeef0202};
94 uint32_t codec
= 1, ppp_codec
= 3;
98 if (getenv("XVMC_VL"))
99 return vl_create_decoder(context
, templ
);
101 if (templ
->entrypoint
!= PIPE_VIDEO_ENTRYPOINT_BITSTREAM
) {
102 debug_printf("%x\n", templ
->entrypoint
);
106 dec
= CALLOC_STRUCT(nouveau_vp3_decoder
);
109 dec
->client
= screen
->client
;
111 nouveau_vp3_decoder_init_common(&dec
->base
);
117 ret
= nouveau_object_new(&screen
->device
->object
, 0,
118 NOUVEAU_FIFO_CHANNEL_CLASS
,
119 &nv04_data
, sizeof(nv04_data
), &dec
->channel
[0]);
122 ret
= nouveau_pushbuf_new(screen
->client
, dec
->channel
[0], 4,
123 32 * 1024, true, &dec
->pushbuf
[0]);
125 for (i
= 1; i
< 3; ++i
) {
126 dec
->channel
[i
] = dec
->channel
[0];
127 dec
->pushbuf
[i
] = dec
->pushbuf
[0];
132 ret
= nouveau_object_mclass(dec
->channel
[0], nv98_decoder_msvld
);
134 ret
= nouveau_object_new(dec
->channel
[0], 0xbeef85b1,
135 nv98_decoder_msvld
[ret
].oclass
, NULL
, 0,
141 ret
= nouveau_object_mclass(dec
->channel
[1], nv98_decoder_mspdec
);
143 ret
= nouveau_object_new(dec
->channel
[1], 0xbeef85b2,
144 nv98_decoder_mspdec
[ret
].oclass
, NULL
, 0,
150 ret
= nouveau_object_mclass(dec
->channel
[2], nv98_decoder_msppp
);
152 ret
= nouveau_object_new(dec
->channel
[2], 0xbeef85b3,
153 nv98_decoder_msppp
[ret
].oclass
, NULL
, 0,
161 BEGIN_NV04(push
[0], SUBC_BSP(NV01_SUBCHAN_OBJECT
), 1);
162 PUSH_DATA (push
[0], dec
->bsp
->handle
);
164 BEGIN_NV04(push
[0], SUBC_BSP(0x180), 5);
165 for (i
= 0; i
< 5; i
++)
166 PUSH_DATA (push
[0], nv04_data
.vram
);
168 BEGIN_NV04(push
[1], SUBC_VP(NV01_SUBCHAN_OBJECT
), 1);
169 PUSH_DATA (push
[1], dec
->vp
->handle
);
171 BEGIN_NV04(push
[1], SUBC_VP(0x180), 6);
172 for (i
= 0; i
< 6; i
++)
173 PUSH_DATA (push
[1], nv04_data
.vram
);
175 BEGIN_NV04(push
[2], SUBC_PPP(NV01_SUBCHAN_OBJECT
), 1);
176 PUSH_DATA (push
[2], dec
->ppp
->handle
);
178 BEGIN_NV04(push
[2], SUBC_PPP(0x180), 5);
179 for (i
= 0; i
< 5; i
++)
180 PUSH_DATA (push
[2], nv04_data
.vram
);
182 dec
->base
.context
= context
;
183 dec
->base
.decode_bitstream
= nv98_decoder_decode_bitstream
;
185 for (i
= 0; i
< NOUVEAU_VP3_VIDEO_QDEPTH
&& !ret
; ++i
)
186 ret
= nouveau_bo_new(screen
->device
, NOUVEAU_BO_VRAM
,
187 0, 1 << 20, NULL
, &dec
->bsp_bo
[i
]);
189 ret
= nouveau_bo_new(screen
->device
, NOUVEAU_BO_VRAM
,
190 0x100, 4 << 20, NULL
, &dec
->inter_bo
[0]);
192 nouveau_bo_ref(dec
->inter_bo
[0], &dec
->inter_bo
[1]);
196 switch (u_reduce_video_profile(templ
->profile
)) {
197 case PIPE_VIDEO_FORMAT_MPEG12
: {
199 assert(templ
->max_references
<= 2);
202 case PIPE_VIDEO_FORMAT_MPEG4
: {
204 tmp_size
= mb(templ
->height
)*16 * mb(templ
->width
)*16;
205 assert(templ
->max_references
<= 2);
208 case PIPE_VIDEO_FORMAT_VC1
: {
209 ppp_codec
= codec
= 2;
210 tmp_size
= mb(templ
->height
)*16 * mb(templ
->width
)*16;
211 assert(templ
->max_references
<= 2);
214 case PIPE_VIDEO_FORMAT_MPEG4_AVC
: {
216 dec
->tmp_stride
= 16 * mb_half(templ
->width
) * nouveau_vp3_video_align(templ
->height
) * 3 / 2;
217 tmp_size
= dec
->tmp_stride
* (templ
->max_references
+ 1);
218 assert(templ
->max_references
<= 16);
222 fprintf(stderr
, "invalid codec\n");
226 ret
= nouveau_bo_new(screen
->device
, NOUVEAU_BO_VRAM
, 0,
227 0x4000, NULL
, &dec
->fw_bo
);
231 ret
= nouveau_vp3_load_firmware(dec
, templ
->profile
, screen
->device
->chipset
);
236 ret
= nouveau_bo_new(screen
->device
, NOUVEAU_BO_VRAM
, 0,
237 0x400, NULL
, &dec
->bitplane_bo
);
242 dec
->ref_stride
= mb(templ
->width
)*16 * (mb_half(templ
->height
)*32 + nouveau_vp3_video_align(templ
->height
)/2);
243 ret
= nouveau_bo_new(screen
->device
, NOUVEAU_BO_VRAM
, 0,
244 dec
->ref_stride
* (templ
->max_references
+2) + tmp_size
,
251 BEGIN_NV04(push
[0], SUBC_BSP(0x200), 2);
252 PUSH_DATA (push
[0], codec
);
253 PUSH_DATA (push
[0], timeout
);
255 BEGIN_NV04(push
[1], SUBC_VP(0x200), 2);
256 PUSH_DATA (push
[1], codec
);
257 PUSH_DATA (push
[1], timeout
);
259 BEGIN_NV04(push
[2], SUBC_PPP(0x200), 2);
260 PUSH_DATA (push
[2], ppp_codec
);
261 PUSH_DATA (push
[2], timeout
);
265 #if NOUVEAU_VP3_DEBUG_FENCE
266 ret
= nouveau_bo_new(screen
->device
, NOUVEAU_BO_GART
|NOUVEAU_BO_MAP
,
267 0, 0x1000, NULL
, &dec
->fence_bo
);
271 nouveau_bo_map(dec
->fence_bo
, NOUVEAU_BO_RDWR
, screen
->client
);
272 dec
->fence_map
= dec
->fence_bo
->map
;
273 dec
->fence_map
[0] = dec
->fence_map
[4] = dec
->fence_map
[8] = 0;
274 dec
->comm
= (struct comm
*)(dec
->fence_map
+ (COMM_OFFSET
/sizeof(*dec
->fence_map
)));
276 /* So lets test if the fence is working? */
277 nouveau_pushbuf_space(push
[0], 16, 1, 0);
278 PUSH_REFN (push
[0], dec
->fence_bo
, NOUVEAU_BO_GART
|NOUVEAU_BO_RDWR
);
279 BEGIN_NV04(push
[0], SUBC_BSP(0x240), 3);
280 PUSH_DATAh(push
[0], dec
->fence_bo
->offset
);
281 PUSH_DATA (push
[0], dec
->fence_bo
->offset
);
282 PUSH_DATA (push
[0], dec
->fence_seq
);
284 BEGIN_NV04(push
[0], SUBC_BSP(0x304), 1);
285 PUSH_DATA (push
[0], 0);
288 nouveau_pushbuf_space(push
[1], 16, 1, 0);
289 PUSH_REFN (push
[1], dec
->fence_bo
, NOUVEAU_BO_GART
|NOUVEAU_BO_RDWR
);
290 BEGIN_NV04(push
[1], SUBC_VP(0x240), 3);
291 PUSH_DATAh(push
[1], (dec
->fence_bo
->offset
+ 0x10));
292 PUSH_DATA (push
[1], (dec
->fence_bo
->offset
+ 0x10));
293 PUSH_DATA (push
[1], dec
->fence_seq
);
295 BEGIN_NV04(push
[1], SUBC_VP(0x304), 1);
296 PUSH_DATA (push
[1], 0);
299 nouveau_pushbuf_space(push
[2], 16, 1, 0);
300 PUSH_REFN (push
[2], dec
->fence_bo
, NOUVEAU_BO_GART
|NOUVEAU_BO_RDWR
);
301 BEGIN_NV04(push
[2], SUBC_PPP(0x240), 3);
302 PUSH_DATAh(push
[2], (dec
->fence_bo
->offset
+ 0x20));
303 PUSH_DATA (push
[2], (dec
->fence_bo
->offset
+ 0x20));
304 PUSH_DATA (push
[2], dec
->fence_seq
);
306 BEGIN_NV04(push
[2], SUBC_PPP(0x304), 1);
307 PUSH_DATA (push
[2], 0);
311 while (dec
->fence_seq
> dec
->fence_map
[0] ||
312 dec
->fence_seq
> dec
->fence_map
[4] ||
313 dec
->fence_seq
> dec
->fence_map
[8]) {
314 debug_printf("%u: %u %u %u\n", dec
->fence_seq
, dec
->fence_map
[0], dec
->fence_map
[4], dec
->fence_map
[8]);
317 debug_printf("%u: %u %u %u\n", dec
->fence_seq
, dec
->fence_map
[0], dec
->fence_map
[4], dec
->fence_map
[8]);
323 debug_printf("Cannot create decoder without firmware..\n");
324 dec
->base
.destroy(&dec
->base
);
328 debug_printf("Creation failed: %s (%i)\n", strerror(-ret
), ret
);
329 dec
->base
.destroy(&dec
->base
);
333 struct pipe_video_buffer
*
334 nv98_video_buffer_create(struct pipe_context
*pipe
,
335 const struct pipe_video_buffer
*templat
)
337 return nouveau_vp3_video_buffer_create(
338 pipe
, templat
, NV50_RESOURCE_FLAG_VIDEO
);