1/*
2 * Copyright (c) 2017-2019 Lima Project
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, sub license,
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 (including the
12 * next paragraph) shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#include <string.h>
26
27#include "util/ralloc.h"
28#include "util/u_debug.h"
29#include "util/u_screen.h"
30#include "renderonly/renderonly.h"
31
32#include "drm-uapi/drm_fourcc.h"
33#include "drm-uapi/lima_drm.h"
34
35#include "lima_screen.h"
36#include "lima_context.h"
37#include "lima_resource.h"
38#include "lima_program.h"
39#include "lima_bo.h"
40#include "lima_fence.h"
41#include "ir/lima_ir.h"
42
43#include "xf86drm.h"
44
45static void
46lima_screen_destroy(struct pipe_screen *pscreen)
47{
48   struct lima_screen *screen = lima_screen(pscreen);
49
50   if (lima_dump_command_stream) {
51      fclose(lima_dump_command_stream);
52      lima_dump_command_stream = NULL;
53   }
54
55   slab_destroy_parent(&screen->transfer_pool);
56
57   if (screen->ro)
58      free(screen->ro);
59
60   if (screen->pp_buffer)
61      lima_bo_free(screen->pp_buffer);
62
63   lima_bo_table_fini(screen);
64   ralloc_free(screen);
65}
66
67static const char *
68lima_screen_get_name(struct pipe_screen *pscreen)
69{
70   struct lima_screen *screen = lima_screen(pscreen);
71
72   switch (screen->gpu_type) {
73   case DRM_LIMA_PARAM_GPU_ID_MALI400:
74     return "Mali400";
75   case DRM_LIMA_PARAM_GPU_ID_MALI450:
76     return "Mali450";
77   }
78
79   return NULL;
80}
81
82static const char *
83lima_screen_get_vendor(struct pipe_screen *pscreen)
84{
85   return "lima";
86}
87
88static const char *
89lima_screen_get_device_vendor(struct pipe_screen *pscreen)
90{
91   return "ARM";
92}
93
94static int
95lima_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
96{
97   switch (param) {
98   case PIPE_CAP_NPOT_TEXTURES:
99   case PIPE_CAP_BLEND_EQUATION_SEPARATE:
100   case PIPE_CAP_ACCELERATED:
101   case PIPE_CAP_UMA:
102   case PIPE_CAP_NATIVE_FENCE_FD:
103      return 1;
104
105   /* Unimplemented, but for exporting OpenGL 2.0 */
106   case PIPE_CAP_OCCLUSION_QUERY:
107   case PIPE_CAP_POINT_SPRITE:
108      return 1;
109
110   /* not clear supported */
111   case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT:
112   case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT:
113   case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER:
114   case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER:
115      return 1;
116
117   case PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL:
118      return 1;
119
120   case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
121   case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
122   case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
123      return LIMA_MAX_MIP_LEVELS;
124
125   case PIPE_CAP_VENDOR_ID:
126      return 0x13B5;
127
128   case PIPE_CAP_VIDEO_MEMORY:
129      return 0;
130
131   case PIPE_CAP_PCI_GROUP:
132   case PIPE_CAP_PCI_BUS:
133   case PIPE_CAP_PCI_DEVICE:
134   case PIPE_CAP_PCI_FUNCTION:
135      return 0;
136
137   case PIPE_CAP_PREFER_BLIT_BASED_TEXTURE_TRANSFER:
138      return 0;
139
140   default:
141      return u_pipe_screen_get_param_defaults(pscreen, param);
142   }
143}
144
145static float
146lima_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_capf param)
147{
148   switch (param) {
149   case PIPE_CAPF_MAX_LINE_WIDTH:
150   case PIPE_CAPF_MAX_LINE_WIDTH_AA:
151   case PIPE_CAPF_MAX_POINT_WIDTH:
152   case PIPE_CAPF_MAX_POINT_WIDTH_AA:
153      return 255.0f;
154   case PIPE_CAPF_MAX_TEXTURE_ANISOTROPY:
155      return 16.0f;
156   case PIPE_CAPF_MAX_TEXTURE_LOD_BIAS:
157      return 16.0f;
158
159   default:
160      return 0.0f;
161   }
162}
163
164static int
165get_vertex_shader_param(struct lima_screen *screen,
166                        enum pipe_shader_cap param)
167{
168   switch (param) {
169   case PIPE_SHADER_CAP_MAX_INSTRUCTIONS:
170   case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS:
171   case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS:
172   case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS:
173      return 16384; /* need investigate */
174
175   case PIPE_SHADER_CAP_MAX_INPUTS:
176      return 16; /* attributes */
177
178   case PIPE_SHADER_CAP_MAX_OUTPUTS:
179      return LIMA_MAX_VARYING_NUM; /* varying */
180
181   case PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE:
182      return 4096; /* need investigate */
183   case PIPE_SHADER_CAP_MAX_CONST_BUFFERS:
184      return 1;
185
186   case PIPE_SHADER_CAP_PREFERRED_IR:
187      return PIPE_SHADER_IR_NIR;
188
189   case PIPE_SHADER_CAP_MAX_TEMPS:
190      return 256; /* need investigate */
191
192   default:
193      return 0;
194   }
195}
196
197static int
198get_fragment_shader_param(struct lima_screen *screen,
199                          enum pipe_shader_cap param)
200{
201   switch (param) {
202   case PIPE_SHADER_CAP_MAX_INSTRUCTIONS:
203   case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS:
204   case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS:
205   case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS:
206      return 16384; /* need investigate */
207
208   case PIPE_SHADER_CAP_MAX_INPUTS:
209      return LIMA_MAX_VARYING_NUM - 1; /* varying, minus gl_Position */
210
211   case PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE:
212      return 4096; /* need investigate */
213   case PIPE_SHADER_CAP_MAX_CONST_BUFFERS:
214      return 1;
215
216   case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS:
217      return 16; /* need investigate */
218
219   case PIPE_SHADER_CAP_PREFERRED_IR:
220      return PIPE_SHADER_IR_NIR;
221
222   case PIPE_SHADER_CAP_MAX_TEMPS:
223      return 256; /* need investigate */
224
225   default:
226      return 0;
227   }
228}
229
230static int
231lima_screen_get_shader_param(struct pipe_screen *pscreen,
232                             enum pipe_shader_type shader,
233                             enum pipe_shader_cap param)
234{
235   struct lima_screen *screen = lima_screen(pscreen);
236
237   switch (shader) {
238   case PIPE_SHADER_FRAGMENT:
239      return get_fragment_shader_param(screen, param);
240   case PIPE_SHADER_VERTEX:
241      return get_vertex_shader_param(screen, param);
242
243   default:
244      return 0;
245   }
246}
247
248static boolean
249lima_screen_is_format_supported(struct pipe_screen *pscreen,
250                                enum pipe_format format,
251                                enum pipe_texture_target target,
252                                unsigned sample_count,
253                                unsigned storage_sample_count,
254                                unsigned usage)
255{
256   switch (target) {
257   case PIPE_BUFFER:
258   case PIPE_TEXTURE_1D:
259   case PIPE_TEXTURE_2D:
260      break;
261   default:
262      return FALSE;
263   }
264
265   if (MAX2(1, sample_count) != MAX2(1, storage_sample_count))
266      return false;
267
268   /* be able to support 16, now limit to 4 */
269   if (sample_count > 1 && sample_count != 4)
270      return FALSE;
271
272   if (usage & PIPE_BIND_RENDER_TARGET) {
273      switch (format) {
274      case PIPE_FORMAT_B8G8R8A8_UNORM:
275      case PIPE_FORMAT_B8G8R8X8_UNORM:
276      case PIPE_FORMAT_R8G8B8A8_UNORM:
277      case PIPE_FORMAT_R8G8B8X8_UNORM:
278      case PIPE_FORMAT_Z16_UNORM:
279      case PIPE_FORMAT_Z24_UNORM_S8_UINT:
280      case PIPE_FORMAT_Z24X8_UNORM:
281         break;
282      default:
283         return FALSE;
284      }
285   }
286
287   if (usage & PIPE_BIND_DEPTH_STENCIL) {
288      switch (format) {
289      case PIPE_FORMAT_Z16_UNORM:
290      case PIPE_FORMAT_Z24_UNORM_S8_UINT:
291      case PIPE_FORMAT_Z24X8_UNORM:
292         break;
293      default:
294         return FALSE;
295      }
296   }
297
298   if (usage & PIPE_BIND_VERTEX_BUFFER) {
299      switch (format) {
300      case PIPE_FORMAT_R32G32B32_FLOAT:
301         break;
302      default:
303         return FALSE;
304      }
305   }
306
307   if (usage & PIPE_BIND_INDEX_BUFFER) {
308      switch (format) {
309      case PIPE_FORMAT_I8_UINT:
310      case PIPE_FORMAT_I16_UINT:
311      case PIPE_FORMAT_I32_UINT:
312         break;
313      default:
314         return FALSE;
315      }
316   }
317
318   if (usage & PIPE_BIND_SAMPLER_VIEW) {
319      switch (format) {
320      case PIPE_FORMAT_R8G8B8X8_UNORM:
321      case PIPE_FORMAT_R8G8B8A8_UNORM:
322      case PIPE_FORMAT_B8G8R8X8_UNORM:
323      case PIPE_FORMAT_B8G8R8A8_UNORM:
324      case PIPE_FORMAT_A8B8G8R8_SRGB:
325      case PIPE_FORMAT_B8G8R8A8_SRGB:
326      case PIPE_FORMAT_Z16_UNORM:
327      case PIPE_FORMAT_Z24_UNORM_S8_UINT:
328      case PIPE_FORMAT_Z24X8_UNORM:
329         break;
330      default:
331         return FALSE;
332      }
333   }
334
335   return TRUE;
336}
337
338static const void *
339lima_screen_get_compiler_options(struct pipe_screen *pscreen,
340                                 enum pipe_shader_ir ir,
341                                 enum pipe_shader_type shader)
342{
343   return lima_program_get_compiler_options(shader);
344}
345
346static bool
347lima_screen_query_info(struct lima_screen *screen)
348{
349   struct drm_lima_get_param param;
350
351   memset(&param, 0, sizeof(param));
352   param.param = DRM_LIMA_PARAM_GPU_ID;
353   if (drmIoctl(screen->fd, DRM_IOCTL_LIMA_GET_PARAM, &param))
354      return false;
355
356   switch (param.value) {
357   case DRM_LIMA_PARAM_GPU_ID_MALI400:
358   case DRM_LIMA_PARAM_GPU_ID_MALI450:
359      screen->gpu_type = param.value;
360      break;
361   default:
362      return false;
363   }
364
365   memset(&param, 0, sizeof(param));
366   param.param = DRM_LIMA_PARAM_NUM_PP;
367   if (drmIoctl(screen->fd, DRM_IOCTL_LIMA_GET_PARAM, &param))
368      return false;
369
370   screen->num_pp = param.value;
371
372   return true;
373}
374
375static void
376lima_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen,
377                                   enum pipe_format format, int max,
378                                   uint64_t *modifiers,
379                                   unsigned int *external_only,
380                                   int *count)
381{
382   uint64_t available_modifiers[] = {
383      DRM_FORMAT_MOD_LINEAR,
384   };
385
386   if (!modifiers) {
387      *count = ARRAY_SIZE(available_modifiers);
388      return;
389   }
390
391   for (int i = 0; i < *count; i++) {
392      modifiers[i] = available_modifiers[i];
393      if (external_only)
394         external_only = false;
395   }
396}
397
398static const struct debug_named_value debug_options[] = {
399        { "gp",       LIMA_DEBUG_GP,
400          "print GP shader compiler result of each stage" },
401        { "pp",       LIMA_DEBUG_PP,
402          "print PP shader compiler result of each stage" },
403        { "dump",     LIMA_DEBUG_DUMP,
404          "dump GPU command stream to $PWD/lima.dump" },
405        { NULL }
406};
407
408DEBUG_GET_ONCE_FLAGS_OPTION(lima_debug, "LIMA_DEBUG", debug_options, 0)
409uint32_t lima_debug;
410
411static void
412lima_screen_parse_env(void)
413{
414   lima_debug = debug_get_option_lima_debug();
415
416   if (lima_debug & LIMA_DEBUG_DUMP) {
417      const char *dump_command = "lima.dump";
418      printf("lima: dump command stream to file %s\n", dump_command);
419      lima_dump_command_stream = fopen(dump_command, "w");
420      if (!lima_dump_command_stream)
421         fprintf(stderr, "lima: fail to open command stream log file %s\n",
422                 dump_command);
423   }
424
425   lima_ctx_num_plb = debug_get_num_option("LIMA_CTX_NUM_PLB", LIMA_CTX_PLB_DEF_NUM);
426   if (lima_ctx_num_plb > LIMA_CTX_PLB_MAX_NUM ||
427       lima_ctx_num_plb < LIMA_CTX_PLB_MIN_NUM) {
428      fprintf(stderr, "lima: LIMA_CTX_NUM_PLB %d out of range [%d %d], "
429              "reset to default %d\n", lima_ctx_num_plb, LIMA_CTX_PLB_MIN_NUM,
430              LIMA_CTX_PLB_MAX_NUM, LIMA_CTX_PLB_DEF_NUM);
431      lima_ctx_num_plb = LIMA_CTX_PLB_DEF_NUM;
432   }
433
434   lima_ppir_force_spilling = debug_get_num_option("LIMA_PPIR_FORCE_SPILLING", 0);
435   if (lima_ppir_force_spilling < 0) {
436      fprintf(stderr, "lima: LIMA_PPIR_FORCE_SPILLING %d less than 0, "
437              "reset to default 0\n", lima_ppir_force_spilling);
438      lima_ppir_force_spilling = 0;
439   }
440}
441
442struct pipe_screen *
443lima_screen_create(int fd, struct renderonly *ro)
444{
445   struct lima_screen *screen;
446
447   screen = rzalloc(NULL, struct lima_screen);
448   if (!screen)
449      return NULL;
450
451   screen->fd = fd;
452
453   if (!lima_screen_query_info(screen))
454      goto err_out0;
455
456   if (!lima_bo_table_init(screen))
457      goto err_out0;
458
459   screen->pp_ra = ppir_regalloc_init(screen);
460   if (!screen->pp_ra)
461      goto err_out1;
462
463   screen->pp_buffer = lima_bo_create(screen, pp_buffer_size, 0);
464   if (!screen->pp_buffer)
465      goto err_out1;
466
467   /* fs program for clear buffer?
468    * const0 1 0 0 -1.67773, mov.v0 $0 ^const0.xxxx, stop
469    */
470   static const uint32_t pp_clear_program[] = {
471      0x00020425, 0x0000000c, 0x01e007cf, 0xb0000000,
472      0x000005f5, 0x00000000, 0x00000000, 0x00000000,
473   };
474   memcpy(lima_bo_map(screen->pp_buffer) + pp_clear_program_offset,
475          pp_clear_program, sizeof(pp_clear_program));
476
477   /* copy texture to framebuffer, used to reload gpu tile buffer
478    * load.v $1 0.xy, texld_2d 0, mov.v0 $0 ^tex_sampler, sync, stop
479    */
480   static const uint32_t pp_reload_program[] = {
481      0x000005e6, 0xf1003c20, 0x00000000, 0x39001000,
482      0x00000e4e, 0x000007cf, 0x00000000, 0x00000000,
483   };
484   memcpy(lima_bo_map(screen->pp_buffer) + pp_reload_program_offset,
485          pp_reload_program, sizeof(pp_reload_program));
486
487   /* 0/1/2 vertex index for reload/clear draw */
488   static const uint8_t pp_shared_index[] = { 0, 1, 2 };
489   memcpy(lima_bo_map(screen->pp_buffer) + pp_shared_index_offset,
490          pp_shared_index, sizeof(pp_shared_index));
491
492   /* 4096x4096 gl pos used for partial clear */
493   static const float pp_clear_gl_pos[] = {
494      4096, 0,    1, 1,
495      0,    0,    1, 1,
496      0,    4096, 1, 1,
497   };
498   memcpy(lima_bo_map(screen->pp_buffer) + pp_clear_gl_pos_offset,
499          pp_clear_gl_pos, sizeof(pp_clear_gl_pos));
500
501   /* is pp frame render state static? */
502   uint32_t *pp_frame_rsw = lima_bo_map(screen->pp_buffer) + pp_frame_rsw_offset;
503   memset(pp_frame_rsw, 0, 0x40);
504   pp_frame_rsw[8] = 0x0000f008;
505   pp_frame_rsw[9] = screen->pp_buffer->va + pp_clear_program_offset;
506   pp_frame_rsw[13] = 0x00000100;
507
508   if (ro) {
509      screen->ro = renderonly_dup(ro);
510      if (!screen->ro) {
511         fprintf(stderr, "Failed to dup renderonly object\n");
512         goto err_out2;
513      }
514   }
515
516   screen->base.destroy = lima_screen_destroy;
517   screen->base.get_name = lima_screen_get_name;
518   screen->base.get_vendor = lima_screen_get_vendor;
519   screen->base.get_device_vendor = lima_screen_get_device_vendor;
520   screen->base.get_param = lima_screen_get_param;
521   screen->base.get_paramf = lima_screen_get_paramf;
522   screen->base.get_shader_param = lima_screen_get_shader_param;
523   screen->base.context_create = lima_context_create;
524   screen->base.is_format_supported = lima_screen_is_format_supported;
525   screen->base.get_compiler_options = lima_screen_get_compiler_options;
526   screen->base.query_dmabuf_modifiers = lima_screen_query_dmabuf_modifiers;
527
528   lima_resource_screen_init(screen);
529   lima_fence_screen_init(screen);
530
531   slab_create_parent(&screen->transfer_pool, sizeof(struct lima_transfer), 16);
532
533   screen->refcnt = 1;
534
535   lima_screen_parse_env();
536
537   return &screen->base;
538
539err_out2:
540   lima_bo_free(screen->pp_buffer);
541err_out1:
542   lima_bo_table_fini(screen);
543err_out0:
544   ralloc_free(screen);
545   return NULL;
546}
547