xref: /aosp_15_r20/external/mesa3d/src/amd/vpelib/src/chip/vpe10/vpe10_cmd_builder.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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  *
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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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  * Authors: AMD
23  *
24  */
25 #include "vpe_assert.h"
26 #include "common.h"
27 #include "vpe_priv.h"
28 #include "vpe10_command.h"
29 #include "vpe10_cmd_builder.h"
30 #include "vpe10_vpe_desc_writer.h"
31 #include "reg_helper.h"
32 
33 /***** Internal helpers *****/
34 static void get_np_and_subop(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info,  struct plane_desc_header *header);
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_desc_writer *vpe_desc_writer = &vpe_priv->vpe_desc_writer;
65     struct vpe_buf      *emb_buf  = &cur_bufs->emb_buf;
66     struct vpe_cmd_info *cmd_info = &vpe_priv->vpe_cmd_info[cmd_idx];
67     struct output_ctx   *output_ctx;
68     struct pipe_ctx     *pipe_ctx = NULL;
69     uint32_t             i, j;
70 
71     vpe_desc_writer->init(vpe_desc_writer, &cur_bufs->cmd_buf, cmd_info->cd);
72 
73     // plane descriptor
74     builder->build_plane_descriptor(vpe_priv, emb_buf, cmd_idx);
75 
76     vpe_desc_writer->add_plane_desc(
77         vpe_desc_writer, vpe_priv->plane_desc_writer.base_gpu_va, (uint8_t)emb_buf->tmz);
78 
79     // reclaim any pipe if the owner no longer presents
80     vpe_pipe_reclaim(vpe_priv, cmd_info);
81 
82     config_writer_init(&vpe_priv->config_writer, emb_buf);
83 
84     // frontend programming
85     for (i = 0; i < cmd_info->num_inputs; i++) {
86         bool               reuse;
87         struct stream_ctx *stream_ctx;
88         enum vpe_cmd_type  cmd_type = VPE_CMD_TYPE_COUNT;
89 
90         // keep using the same pipe whenever possible
91         // this would allow reuse of the previous register configs
92         pipe_ctx = vpe_pipe_find_owner(vpe_priv, cmd_info->inputs[i].stream_idx, &reuse);
93         VPE_ASSERT(pipe_ctx);
94 
95         if (!reuse) {
96             vpe_priv->resource.program_frontend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, i, false);
97         } else {
98             if (vpe_priv->init.debug.disable_reuse_bit)
99                 reuse = false;
100 
101             stream_ctx = &vpe_priv->stream_ctx[cmd_info->inputs[i].stream_idx];
102 
103             // frame specific for same type of command
104             if (cmd_info->ops == VPE_CMD_OPS_BG)
105                 cmd_type = VPE_CMD_TYPE_BG;
106             else if (cmd_info->ops == VPE_CMD_OPS_COMPOSITING)
107                 cmd_type = VPE_CMD_TYPE_COMPOSITING;
108             else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_INPUT)
109                 cmd_type = VPE_CMD_TYPE_BG_VSCF_INPUT;
110             else if (cmd_info->ops == VPE_CMD_OPS_BG_VSCF_OUTPUT)
111                 cmd_type = VPE_CMD_TYPE_BG_VSCF_OUTPUT;
112             else {
113                 VPE_ASSERT(0);
114                 return VPE_STATUS_ERROR;
115             }
116 
117             // follow the same order of config generation in "non-reuse" case
118             // stream sharing
119             VPE_ASSERT(stream_ctx->num_configs);
120             for (j = 0; j < stream_ctx->num_configs; j++) {
121                 vpe_desc_writer->add_config_desc(vpe_desc_writer,
122                     stream_ctx->configs[j].config_base_addr, reuse, (uint8_t)emb_buf->tmz);
123             }
124 
125             // stream-op sharing
126             for (j = 0; j < stream_ctx->num_stream_op_configs[cmd_type]; j++) {
127                 vpe_desc_writer->add_config_desc(vpe_desc_writer,
128                     stream_ctx->stream_op_configs[cmd_type][j].config_base_addr, reuse,
129                     (uint8_t)emb_buf->tmz);
130             }
131 
132             // command specific
133             vpe_priv->resource.program_frontend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, i, true);
134         }
135     }
136 
137     VPE_ASSERT(pipe_ctx);
138 
139     // If config writer has been crashed due to buffer overflow
140     if (vpe_priv->config_writer.status != VPE_STATUS_OK) {
141         return vpe_priv->config_writer.status;
142     }
143 
144     // backend programming
145     output_ctx = &vpe_priv->output_ctx;
146     if (!output_ctx->num_configs) {
147         vpe_priv->resource.program_backend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, false);
148     } else {
149         bool reuse = !vpe_priv->init.debug.disable_reuse_bit;
150         // re-use output register configs
151         for (j = 0; j < output_ctx->num_configs; j++) {
152             vpe_desc_writer->add_config_desc(vpe_desc_writer,
153                 output_ctx->configs[j].config_base_addr, reuse, (uint8_t)emb_buf->tmz);
154         }
155 
156         vpe_priv->resource.program_backend(vpe_priv, pipe_ctx->pipe_idx, cmd_idx, true);
157     }
158 
159     /* If writer crashed due to buffer overflow */
160     if (vpe_desc_writer->status != VPE_STATUS_OK) {
161         return vpe_desc_writer->status;
162     }
163     vpe_desc_writer->complete(vpe_desc_writer);
164 
165     return VPE_STATUS_OK;
166 }
167 
vpe10_build_plane_descriptor(struct vpe_priv * vpe_priv,struct vpe_buf * buf,uint32_t cmd_idx)168 enum vpe_status vpe10_build_plane_descriptor(
169     struct vpe_priv *vpe_priv, struct vpe_buf *buf, uint32_t cmd_idx)
170 {
171     struct stream_ctx       *stream_ctx;
172     struct vpe_surface_info *surface_info;
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     struct plane_desc_header  header            = {0};
179     struct cmd_builder       *builder           = &vpe_priv->resource.cmd_builder;
180     struct plane_desc_writer *plane_desc_writer = &vpe_priv->plane_desc_writer;
181 
182     cmd_info = &vpe_priv->vpe_cmd_info[cmd_idx];
183 
184     VPE_ASSERT(cmd_info->num_inputs == 1);
185 
186     // obtains number of planes for each source/destination stream
187     get_np_and_subop(vpe_priv, cmd_info, &header);
188 
189     plane_desc_writer->init(&vpe_priv->plane_desc_writer, buf, &header);
190     stream_idx   = cmd_info->inputs[0].stream_idx;
191     stream_ctx   = &vpe_priv->stream_ctx[stream_idx];
192     surface_info = &stream_ctx->stream.surface_info;
193 
194     src.tmz      = surface_info->address.tmz_surface;
195     src.swizzle  = surface_info->swizzle;
196     src.rotation = stream_ctx->stream.rotation;
197 
198     if (surface_info->address.type == VPE_PLN_ADDR_TYPE_VIDEO_PROGRESSIVE) {
199         addrloc = &surface_info->address.video_progressive.luma_addr;
200 
201         src.base_addr_lo = addrloc->u.low_part;
202         src.base_addr_hi = (uint32_t)addrloc->u.high_part;
203         src.pitch        = (uint16_t)surface_info->plane_size.surface_pitch;
204         src.viewport_x   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.x;
205         src.viewport_y   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.y;
206         src.viewport_w   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.width;
207         src.viewport_h   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.height;
208         src.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
209 
210         plane_desc_writer->add_source(&vpe_priv->plane_desc_writer, &src, true);
211 
212         if (vpe_is_dual_plane_format(surface_info->format)) {
213             addrloc = &surface_info->address.video_progressive.chroma_addr;
214 
215             src.base_addr_lo = addrloc->u.low_part;
216             src.base_addr_hi = (uint32_t)addrloc->u.high_part;
217             src.pitch        = (uint16_t)surface_info->plane_size.chroma_pitch;
218             src.viewport_x   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.x;
219             src.viewport_y   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.y;
220             src.viewport_w   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.width;
221             src.viewport_h   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport_c.height;
222             src.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 1));
223 
224             plane_desc_writer->add_source(&vpe_priv->plane_desc_writer, &src, false);
225         }
226     } else {
227         addrloc = &surface_info->address.grph.addr;
228 
229         src.base_addr_lo = addrloc->u.low_part;
230         src.base_addr_hi = (uint32_t)addrloc->u.high_part;
231         src.pitch        = (uint16_t)surface_info->plane_size.surface_pitch;
232         src.viewport_x   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.x;
233         src.viewport_y   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.y;
234         src.viewport_w   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.width;
235         src.viewport_h   = (uint16_t)cmd_info->inputs[0].scaler_data.viewport.height;
236         src.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
237 
238         plane_desc_writer->add_source(&vpe_priv->plane_desc_writer, &src, true);
239     }
240 
241     surface_info = &vpe_priv->output_ctx.surface;
242 
243     VPE_ASSERT(surface_info->address.type == VPE_PLN_ADDR_TYPE_GRAPHICS);
244 
245     addrloc = &surface_info->address.grph.addr;
246 
247     dst.tmz     = surface_info->address.tmz_surface;
248     dst.swizzle = surface_info->swizzle;
249 
250     if (stream_ctx->flip_horizonal_output)
251         dst.mirror = VPE_MIRROR_HORIZONTAL;
252     else
253         dst.mirror = VPE_MIRROR_NONE;
254 
255     dst.base_addr_lo = addrloc->u.low_part;
256     dst.base_addr_hi = (uint32_t)addrloc->u.high_part;
257     dst.pitch        = (uint16_t)surface_info->plane_size.surface_pitch;
258     dst.viewport_x   = (uint16_t)cmd_info->outputs[0].dst_viewport.x;
259     dst.viewport_y   = (uint16_t)cmd_info->outputs[0].dst_viewport.y;
260     dst.viewport_w   = (uint16_t)cmd_info->outputs[0].dst_viewport.width;
261     dst.viewport_h   = (uint16_t)cmd_info->outputs[0].dst_viewport.height;
262     dst.elem_size    = (uint8_t)(vpe_get_element_size(surface_info->format, 0));
263 
264     plane_desc_writer->add_destination(&vpe_priv->plane_desc_writer, &dst, true);
265 
266     return vpe_priv->plane_desc_writer.status;
267 }
268 
get_np_and_subop(struct vpe_priv * vpe_priv,struct vpe_cmd_info * cmd_info,struct plane_desc_header * header)269 static void get_np_and_subop(struct vpe_priv *vpe_priv, struct vpe_cmd_info *cmd_info,
270     struct plane_desc_header *header)
271 {
272     header->npd1 = 0;
273 
274     header->subop = VPE_PLANE_CFG_SUBOP_1_TO_1;
275 
276     if (cmd_info->num_inputs == 1) {
277         header->nps1 = 0;
278         if (vpe_is_dual_plane_format(
279                 vpe_priv->stream_ctx[cmd_info->inputs[0].stream_idx].stream.surface_info.format))
280             header->nps0 = VPE_PLANE_CFG_TWO_PLANES;
281         else
282             header->nps0 = VPE_PLANE_CFG_ONE_PLANE;
283     } else if (cmd_info->num_inputs == 2) {
284         if (vpe_is_dual_plane_format(
285                 vpe_priv->stream_ctx[cmd_info->inputs[0].stream_idx].stream.surface_info.format))
286             header->nps0 = VPE_PLANE_CFG_TWO_PLANES;
287         else
288             header->nps0 = VPE_PLANE_CFG_ONE_PLANE;
289 
290         if (vpe_is_dual_plane_format(
291                 vpe_priv->stream_ctx[cmd_info->inputs[1].stream_idx].stream.surface_info.format))
292             header->nps1 = VPE_PLANE_CFG_TWO_PLANES;
293         else
294             header->nps1 = VPE_PLANE_CFG_ONE_PLANE;
295     } else {
296         header->nps0 = 0;
297         header->nps1 = 0;
298         header->npd0 = 0;
299         return;
300     }
301 
302     if (vpe_is_dual_plane_format(vpe_priv->output_ctx.surface.format))
303         header->npd0 = 1;
304     else
305         header->npd0 = 0;
306 }
307 
vpe_get_element_size(enum vpe_surface_pixel_format format,int plane_idx)308 static enum VPE_PLANE_CFG_ELEMENT_SIZE vpe_get_element_size(
309     enum vpe_surface_pixel_format format, int plane_idx)
310 {
311     switch (format) {
312         // nv12/21
313     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
314     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
315         if (plane_idx == 0)
316             return VPE_PLANE_CFG_ELEMENT_SIZE_8BPE;
317         else
318             return VPE_PLANE_CFG_ELEMENT_SIZE_16BPE;
319         // P010
320     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
321     case VPE_SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
322         if (plane_idx == 0)
323             return VPE_PLANE_CFG_ELEMENT_SIZE_16BPE;
324         else
325             return VPE_PLANE_CFG_ELEMENT_SIZE_32BPE;
326         // 64bpp
327     case VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
328     case VPE_SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
329     case VPE_SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
330     case VPE_SURFACE_PIXEL_FORMAT_GRPH_RGBA16161616F:
331     case VPE_SURFACE_PIXEL_FORMAT_GRPH_BGRA16161616F:
332         return VPE_PLANE_CFG_ELEMENT_SIZE_64BPE;
333     default:
334         break;
335     }
336     return VPE_PLANE_CFG_ELEMENT_SIZE_32BPE;
337 }
338