• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2022 Advanced Micro Devices, Inc.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the "Software"),
5  * to deal in the Software without restriction, including without limitation
6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7  * and/or sell copies of the Software, and to permit persons to whom the
8  * Software is furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
16  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
17  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
18  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19  * OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Authors: AMD
22  *
23  */
24 #include "vpe_assert.h"
25 #include "common.h"
26 #include "vpe_priv.h"
27 #include "vpe_command.h"
28 #include "vpe10_cmd_builder.h"
29 #include "plane_desc_writer.h"
30 #include "reg_helper.h"
31 
32 /***** Internal helpers *****/
33 static void get_np(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info, int32_t *nps0,
34     int32_t *nps1, int32_t *npd0, int32_t *npd1);
35 
36 static enum VPE_PLANE_CFG_ELEMENT_SIZE vpe_get_element_size(
37     enum vpe_surface_pixel_format format, int plane_idx);
38 
vpe10_construct_cmd_builder(struct vpe_priv * vpe_priv,struct cmd_builder * builder)39 void vpe10_construct_cmd_builder(struct vpe_priv *vpe_priv, struct cmd_builder *builder)
40 {
41     builder->build_noops            = vpe10_build_noops;
42     builder->build_vpe_cmd          = vpe10_build_vpe_cmd;
43     builder->build_plane_descriptor = vpe10_build_plane_descriptor;
44 }
45 
vpe10_build_noops(struct vpe_priv * vpe_priv,uint32_t ** ppbuf,uint32_t num_dwords)46 enum vpe_status vpe10_build_noops(struct vpe_priv *vpe_priv, uint32_t **ppbuf, uint32_t num_dwords)
47 {
48     uint32_t  i;
49     uint32_t *buffer = *ppbuf;
50     uint32_t  noop   = VPE_CMD_HEADER(VPE_CMD_OPCODE_NOP, 0);
51 
52     for (i = 0; i < num_dwords; i++)
53         *buffer++ = noop;
54 
55     *ppbuf = buffer;
56 
57     return VPE_STATUS_OK;
58 }
59 
vpe10_build_vpe_cmd(struct vpe_priv * vpe_priv,struct vpe_build_bufs * cur_bufs,uint32_t cmd_idx)60 enum vpe_status vpe10_build_vpe_cmd(
61     struct vpe_priv *vpe_priv, struct vpe_build_bufs *cur_bufs, uint32_t cmd_idx)
62 {
63     struct cmd_builder  *builder  = &vpe_priv->resource.cmd_builder;
64     struct vpe_buf      *emb_buf  = &cur_bufs->emb_buf;
65     struct vpe_cmd_info *cmd_info = &vpe_priv->vpe_cmd_info[cmd_idx];
66     struct output_ctx   *output_ctx;
67     struct pipe_ctx     *pipe_ctx = NULL;
68     uint32_t             i, j;
69 
70     vpe_desc_writer_init(&vpe_priv->vpe_desc_writer, &cur_bufs->cmd_buf, cmd_info->cd);
71 
72     // plane descriptor
73     builder->build_plane_descriptor(vpe_priv, emb_buf, cmd_idx);
74 
75     vpe_desc_writer_add_plane_desc(
76         &vpe_priv->vpe_desc_writer, vpe_priv->plane_desc_writer.base_gpu_va, emb_buf->tmz);
77 
78     // reclaim any pipe if the owner no longer presents
79     vpe_pipe_reclaim(vpe_priv, cmd_info);
80 
81     config_writer_init(&vpe_priv->config_writer, emb_buf);
82 
83     // frontend programming
84     for (i = 0; i < cmd_info->num_inputs; i++) {
85         bool               reuse;
86         struct stream_ctx *stream_ctx;
87         enum vpe_cmd_type  cmd_type = VPE_CMD_TYPE_COUNT;
88 
89         // keep using the same pipe whenever possible
90         // this would allow reuse of the previous register configs
91         pipe_ctx = vpe_pipe_find_owner(vpe_priv, cmd_info->inputs[i].stream_idx, &reuse);
92         VPE_ASSERT(pipe_ctx);
93 
94         if (!reuse) {
95             vpe_priv->resource.program_frontend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, i, false);
96         } else {
97             if (vpe_priv->init.debug.disable_reuse_bit)
98                 reuse = false;
99 
100             stream_ctx = &vpe_priv->stream_ctx[cmd_info->inputs[i].stream_idx];
101 
102             // frame specific for same type of command
103             if (cmd_info->ops == VPE_CMD_OPS_BG)
104                 cmd_type = VPE_CMD_TYPE_BG;
105             else if (cmd_info->ops == VPE_CMD_OPS_COMPOSITING)
106                 cmd_type = VPE_CMD_TYPE_COMPOSITING;
107             else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_INPUT)
108                 cmd_type = VPE_CMD_TYPE_BG_VSCF_INPUT;
109             else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_OUTPUT)
110                 cmd_type = VPE_CMD_TYPE_BG_VSCF_OUTPUT;
111             else {
112                 VPE_ASSERT(0);
113                 return VPE_STATUS_ERROR;
114             }
115 
116             // follow the same order of config generation in "non-reuse" case
117             // stream sharing
118             VPE_ASSERT(stream_ctx->num_configs);
119             for (j = 0; j < stream_ctx->num_configs; j++) {
120                 vpe_desc_writer_add_config_desc(&vpe_priv->vpe_desc_writer,
121                     stream_ctx->configs[j].config_base_addr, reuse, emb_buf->tmz);
122             }
123 
124             // stream-op sharing
125             for (j = 0; j < stream_ctx->num_stream_op_configs[cmd_type]; j++) {
126                 vpe_desc_writer_add_config_desc(&vpe_priv->vpe_desc_writer,
127                     stream_ctx->stream_op_configs[cmd_type][j].config_base_addr, reuse,
128                     emb_buf->tmz);
129             }
130 
131             // command specific
132             vpe_priv->resource.program_frontend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, i, true);
133         }
134     }
135 
136     VPE_ASSERT(pipe_ctx);
137 
138     // If config writer has been crashed due to buffer overflow
139     if (vpe_priv->config_writer.status != VPE_STATUS_OK) {
140         return vpe_priv->config_writer.status;
141     }
142 
143     // backend programming
144     output_ctx = &vpe_priv->output_ctx;
145     if (!output_ctx->num_configs) {
146         vpe_priv->resource.program_backend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, false);
147     } else {
148         bool reuse = !vpe_priv->init.debug.disable_reuse_bit;
149         // re-use output register configs
150         for (j = 0; j < output_ctx->num_configs; j++) {
151             vpe_desc_writer_add_config_desc(&vpe_priv->vpe_desc_writer,
152                 output_ctx->configs[j].config_base_addr, reuse, emb_buf->tmz);
153         }
154 
155         vpe_priv->resource.program_backend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, true);
156     }
157 
158     /* If writer crashed due to buffer overflow */
159     if (vpe_priv->vpe_desc_writer.status != VPE_STATUS_OK) {
160         return vpe_priv->vpe_desc_writer.status;
161     }
162     vpe_desc_writer_complete(&vpe_priv->vpe_desc_writer);
163 
164     return VPE_STATUS_OK;
165 }
166 
vpe10_build_plane_descriptor(struct vpe_priv * vpe_priv,struct vpe_buf * buf,uint32_t cmd_idx)167 enum vpe_status vpe10_build_plane_descriptor(
168     struct vpe_priv *vpe_priv, struct vpe_buf *buf, uint32_t cmd_idx)
169 {
170     struct stream_ctx       *stream_ctx;
171     struct vpe_surface_info *surface_info;
172     int32_t                  nps0, nps1, npd0, npd1;
173     int32_t                  stream_idx;
174     struct vpe_cmd_info     *cmd_info;
175     PHYSICAL_ADDRESS_LOC    *addrloc;
176     struct plane_desc_src    src;
177     struct plane_desc_dst    dst;
178 
179     cmd_info = &vpe_priv->vpe_cmd_info[cmd_idx];
180 
181     VPE_ASSERT(cmd_info->num_inputs == 1);
182 
183     // obtains number of planes for each source/destination stream
184     get_np(vpe_priv, cmd_info, &nps0, &nps1, &npd0, &npd1);
185 
186     plane_desc_writer_init(
187         &vpe_priv->plane_desc_writer, buf, nps0, npd0, nps1, npd1, VPE_PLANE_CFG_SUBOP_1_TO_1);
188 
189     stream_idx   = cmd_info->inputs[0].stream_idx;
190     stream_ctx   = &vpe_priv->stream_ctx[stream_idx];
191     surface_info = &stream_ctx->stream.surface_info;
192 
193     src.tmz      = surface_info->address.tmz_surface;
194     src.swizzle  = surface_info->swizzle;
195     src.rotation = stream_ctx->stream.rotation;
196 
197     if (surface_info->address.type == VPE_PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) {
198         addrloc = &surface_info->address.video_progressive.luma_addr;
199 
200         src.base_addr_lo = addrloc->u.low_part;
201         src.base_addr_hi = (uint32_t)addrloc->u.high_part;
202         src.pitch        = (uint16_t)surface_info->plane_size.surface_pitch;
203         src.viewport_x   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.x;
204         src.viewport_y   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.y;
205         src.viewport_w   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.width;
206         src.viewport_h   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.height;
207         src.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
208 
209         plane_desc_writer_add_source(&vpe_priv->plane_desc_writer, &src, true);
210 
211         if (vpe_is_dual_plane_format(surface_info->format)) {
212             addrloc = &surface_info->address.video_progressive.chroma_addr;
213 
214             src.base_addr_lo = addrloc->u.low_part;
215             src.base_addr_hi = (uint32_t)addrloc->u.high_part;
216             src.pitch        = (uint16_t)surface_info->plane_size.chroma_pitch;
217             src.viewport_x   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.x;
218             src.viewport_y   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.y;
219             src.viewport_w   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.width;
220             src.viewport_h   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.height;
221             src.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 1));
222 
223             plane_desc_writer_add_source(&vpe_priv->plane_desc_writer, &src, false);
224         }
225     } else {
226         addrloc = &surface_info->address.grph.addr;
227 
228         src.base_addr_lo = addrloc->u.low_part;
229         src.base_addr_hi = (uint32_t)addrloc->u.high_part;
230         src.pitch        = (uint16_t)surface_info->plane_size.surface_pitch;
231         src.viewport_x   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.x;
232         src.viewport_y   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.y;
233         src.viewport_w   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.width;
234         src.viewport_h   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.height;
235         src.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
236 
237         plane_desc_writer_add_source(&vpe_priv->plane_desc_writer, &src, true);
238     }
239 
240     surface_info = &vpe_priv->output_ctx.surface;
241 
242     VPE_ASSERT(surface_info->address.type == VPE_PLN_ADDR_TYPE_GRAPHICS);
243 
244     addrloc = &surface_info->address.grph.addr;
245 
246     dst.tmz     = surface_info->address.tmz_surface;
247     dst.swizzle = surface_info->swizzle;
248 
249     if (stream_ctx->flip_horizonal_output)
250         dst.mirror = VPE_MIRROR_HORIZONTAL;
251     else
252         dst.mirror = VPE_MIRROR_NONE;
253 
254     dst.base_addr_lo = addrloc->u.low_part;
255     dst.base_addr_hi = (uint32_t)addrloc->u.high_part;
256     dst.pitch        = (uint16_t)surface_info->plane_size.surface_pitch;
257     dst.viewport_x   = (uint16_t)cmd_info->dst_viewport.x;
258     dst.viewport_y   = (uint16_t)cmd_info->dst_viewport.y;
259     dst.viewport_w   = (uint16_t)cmd_info->dst_viewport.width;
260     dst.viewport_h   = (uint16_t)cmd_info->dst_viewport.height;
261     dst.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
262 
263     plane_desc_writer_add_destination(&vpe_priv->plane_desc_writer, &dst, true);
264 
265     return vpe_priv->plane_desc_writer.status;
266 }
267 
get_np(struct vpe_priv * vpe_priv,struct vpe_cmd_info * cmd_info,int32_t * nps0,int32_t * nps1,int32_t * npd0,int32_t * npd1)268 static void get_np(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info, int32_t *nps0,
269     int32_t *nps1, int32_t *npd0, int32_t *npd1)
270 {
271     *npd1 = 0;
272 
273     if (cmd_info->num_inputs == 1) {
274         *nps1 = 0;
275         if (vpe_is_dual_plane_format(
276                 vpe_priv->stream_ctx[cmd_info->inputs[0].stream_idx].stream.surface_info.format))
277             *nps0 = VPE_PLANE_CFG_TWO_PLANES;
278         else
279             *nps0 = VPE_PLANE_CFG_ONE_PLANE;
280     } else if (cmd_info->num_inputs == 2) {
281         if (vpe_is_dual_plane_format(
282                 vpe_priv->stream_ctx[cmd_info->inputs[0].stream_idx].stream.surface_info.format))
283             *nps0 = VPE_PLANE_CFG_TWO_PLANES;
284         else
285             *nps0 = VPE_PLANE_CFG_ONE_PLANE;
286 
287         if (vpe_is_dual_plane_format(
288                 vpe_priv->stream_ctx[cmd_info->inputs[1].stream_idx].stream.surface_info.format))
289             *nps1 = VPE_PLANE_CFG_TWO_PLANES;
290         else
291             *nps1 = VPE_PLANE_CFG_ONE_PLANE;
292     } else {
293         *nps0 = 0;
294         *nps1 = 0;
295         *npd0 = 0;
296         return;
297     }
298 
299     if (vpe_is_dual_plane_format(vpe_priv->output_ctx.surface.format))
300         *npd0 = 1;
301     else
302         *npd0 = 0;
303 }
304 
vpe_get_element_size(enum vpe_surface_pixel_format format,int plane_idx)305 static enum VPE_PLANE_CFG_ELEMENT_SIZE vpe_get_element_size(
306     enum vpe_surface_pixel_format format, int plane_idx)
307 {
308     switch (format) {
309         // nv12/21
310     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
311     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
312         if (plane_idx == 0)
313             return VPE_PLANE_CFG_ELEMENT_SIZE_8BPE;
314         else
315             return VPE_PLANE_CFG_ELEMENT_SIZE_16BPE;
316         // P010
317     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
318     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
319         if (plane_idx == 0)
320             return VPE_PLANE_CFG_ELEMENT_SIZE_16BPE;
321         else
322             return VPE_PLANE_CFG_ELEMENT_SIZE_32BPE;
323         // 64bpp
324     case VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
325     case VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
326     case VPE_SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
327     case VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBA16161616F:
328     case VPE_SURFACE_PIXEL_FORMAT_GRPH_BGRA16161616F:
329         return VPE_PLANE_CFG_ELEMENT_SIZE_64BPE;
330     default:
331         break;
332     }
333     return VPE_PLANE_CFG_ELEMENT_SIZE_32BPE;
334 }
335