OSDN Git Service

vc4: Fix a memory leak in the simulator case.
[android-x86/external-mesa.git] / src / gallium / drivers / vc4 / vc4_simulator.c
1 /*
2  * Copyright © 2014 Broadcom
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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * 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 NONINFRINGEMENT.  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 DEALINGS
21  * IN THE SOFTWARE.
22  */
23
24 #ifdef USE_VC4_SIMULATOR
25
26 #include "util/u_memory.h"
27 #include "util/ralloc.h"
28
29 #include "vc4_screen.h"
30 #include "vc4_context.h"
31 #include "kernel/vc4_drv.h"
32 #include "vc4_simulator_validate.h"
33 #include "simpenrose/simpenrose.h"
34
35 #define OVERFLOW_SIZE (32 * 1024 * 1024)
36
37 static struct drm_gem_cma_object *
38 vc4_wrap_bo_with_cma(struct drm_device *dev, struct vc4_bo *bo)
39 {
40         struct vc4_context *vc4 = dev->vc4;
41         struct vc4_screen *screen = vc4->screen;
42         struct drm_vc4_bo *drm_bo = CALLOC_STRUCT(drm_vc4_bo);
43         struct drm_gem_cma_object *obj = &drm_bo->base;
44         uint32_t size = align(bo->size, 4096);
45
46         drm_bo->bo = bo;
47         obj->base.size = size;
48         obj->base.dev = dev;
49         obj->vaddr = screen->simulator_mem_base + dev->simulator_mem_next;
50         obj->paddr = simpenrose_hw_addr(obj->vaddr);
51
52         dev->simulator_mem_next += size;
53         dev->simulator_mem_next = align(dev->simulator_mem_next, 4096);
54         assert(dev->simulator_mem_next <= screen->simulator_mem_size);
55
56         return obj;
57 }
58
59 struct drm_gem_cma_object *
60 drm_gem_cma_create(struct drm_device *dev, size_t size)
61 {
62         struct vc4_context *vc4 = dev->vc4;
63         struct vc4_screen *screen = vc4->screen;
64
65         struct vc4_bo *bo = vc4_bo_alloc(screen, size, "simulator validate");
66         return vc4_wrap_bo_with_cma(dev, bo);
67 }
68
69 static int
70 vc4_simulator_pin_bos(struct drm_device *dev, struct vc4_exec_info *exec)
71 {
72         struct drm_vc4_submit_cl *args = exec->args;
73         struct vc4_context *vc4 = dev->vc4;
74         struct vc4_bo **bos = vc4->bo_pointers.base;
75
76         exec->bo_count = args->bo_handle_count;
77         exec->bo = calloc(exec->bo_count, sizeof(void *));
78         for (int i = 0; i < exec->bo_count; i++) {
79                 struct vc4_bo *bo = bos[i];
80                 struct drm_gem_cma_object *obj = vc4_wrap_bo_with_cma(dev, bo);
81
82                 struct drm_vc4_bo *drm_bo = to_vc4_bo(&obj->base);
83 #if 0
84                 fprintf(stderr, "bo hindex %d: %s\n", i, bo->name);
85 #endif
86
87                 vc4_bo_map(bo);
88                 memcpy(obj->vaddr, bo->map, bo->size);
89
90                 exec->bo[i] = obj;
91
92                 /* The kernel does this validation at shader create ioctl
93                  * time.
94                  */
95                 if (strcmp(bo->name, "code") == 0) {
96                         drm_bo->validated_shader = vc4_validate_shader(obj);
97                         if (!drm_bo->validated_shader)
98                                 abort();
99                 }
100         }
101         return 0;
102 }
103
104 static int
105 vc4_simulator_unpin_bos(struct vc4_exec_info *exec)
106 {
107         for (int i = 0; i < exec->bo_count; i++) {
108                 struct drm_gem_cma_object *obj = exec->bo[i];
109                 struct drm_vc4_bo *drm_bo = to_vc4_bo(&obj->base);
110                 struct vc4_bo *bo = drm_bo->bo;
111
112                 memcpy(bo->map, obj->vaddr, bo->size);
113
114                 if (drm_bo->validated_shader) {
115                         free(drm_bo->validated_shader->texture_samples);
116                         free(drm_bo->validated_shader);
117                 }
118                 free(obj);
119         }
120
121         free(exec->bo);
122
123         return 0;
124 }
125
126 int
127 vc4_simulator_flush(struct vc4_context *vc4, struct drm_vc4_submit_cl *args)
128 {
129         struct vc4_screen *screen = vc4->screen;
130         struct vc4_surface *csurf = vc4_surface(vc4->framebuffer.cbufs[0]);
131         struct vc4_resource *ctex = csurf ? vc4_resource(csurf->base.texture) : NULL;
132         uint32_t winsys_stride = ctex ? ctex->bo->simulator_winsys_stride : 0;
133         uint32_t sim_stride = ctex ? ctex->slices[0].stride : 0;
134         uint32_t row_len = MIN2(sim_stride, winsys_stride);
135         struct vc4_exec_info exec;
136         struct drm_device local_dev = {
137                 .vc4 = vc4,
138                 .simulator_mem_next = OVERFLOW_SIZE,
139         };
140         struct drm_device *dev = &local_dev;
141         int ret;
142
143         memset(&exec, 0, sizeof(exec));
144         list_inithead(&exec.unref_list);
145
146         if (ctex && ctex->bo->simulator_winsys_map) {
147 #if 0
148                 fprintf(stderr, "%dx%d %d %d %d\n",
149                         ctex->base.b.width0, ctex->base.b.height0,
150                         winsys_stride,
151                         sim_stride,
152                         ctex->bo->size);
153 #endif
154
155                 for (int y = 0; y < ctex->base.b.height0; y++) {
156                         memcpy(ctex->bo->map + y * sim_stride,
157                                ctex->bo->simulator_winsys_map + y * winsys_stride,
158                                row_len);
159                 }
160         }
161
162         exec.args = args;
163
164         ret = vc4_simulator_pin_bos(dev, &exec);
165         if (ret)
166                 return ret;
167
168         ret = vc4_cl_validate(dev, &exec);
169         if (ret)
170                 return ret;
171
172         if (exec.ct0ca != exec.ct0ea) {
173                 int bfc = simpenrose_do_binning(exec.ct0ca, exec.ct0ea);
174                 if (bfc != 1) {
175                         fprintf(stderr, "Binning returned %d flushes, should be 1.\n",
176                                 bfc);
177                         fprintf(stderr, "Relocated binning command list:\n");
178                         vc4_dump_cl(screen->simulator_mem_base + exec.ct0ca,
179                                     exec.ct0ea - exec.ct0ca, false);
180                         abort();
181                 }
182         }
183         int rfc = simpenrose_do_rendering(exec.ct1ca, exec.ct1ea);
184         if (rfc != 1) {
185                 fprintf(stderr, "Rendering returned %d frames, should be 1.\n",
186                         rfc);
187                 fprintf(stderr, "Relocated render command list:\n");
188                 vc4_dump_cl(screen->simulator_mem_base + exec.ct1ca,
189                             exec.ct1ea - exec.ct1ca, true);
190                 abort();
191         }
192
193         ret = vc4_simulator_unpin_bos(&exec);
194         if (ret)
195                 return ret;
196
197         list_for_each_entry_safe(struct drm_vc4_bo, bo, &exec.unref_list,
198                                  unref_head) {
199                 list_del(&bo->unref_head);
200                 vc4_bo_unreference(&bo->bo);
201                 free(bo);
202         }
203
204         if (ctex && ctex->bo->simulator_winsys_map) {
205                 for (int y = 0; y < ctex->base.b.height0; y++) {
206                         memcpy(ctex->bo->simulator_winsys_map + y * winsys_stride,
207                                ctex->bo->map + y * sim_stride,
208                                row_len);
209                 }
210         }
211
212         return 0;
213 }
214
215 void
216 vc4_simulator_init(struct vc4_screen *screen)
217 {
218         screen->simulator_mem_size = 256 * 1024 * 1024;
219         screen->simulator_mem_base = ralloc_size(screen,
220                                                  screen->simulator_mem_size);
221
222         /* We supply our own memory so that we can have more aperture
223          * available (256MB instead of simpenrose's default 64MB).
224          */
225         simpenrose_init_hardware_supply_mem(screen->simulator_mem_base,
226                                             screen->simulator_mem_size);
227
228         /* Carve out low memory for tile allocation overflow.  The kernel
229          * should be automatically handling overflow memory setup on real
230          * hardware, but for simulation we just get one shot to set up enough
231          * overflow memory before execution.  This overflow mem will be used
232          * up over the whole lifetime of simpenrose (not reused on each
233          * flush), so it had better be big.
234          */
235         simpenrose_supply_overflow_mem(0, OVERFLOW_SIZE);
236 }
237
238 #endif /* USE_VC4_SIMULATOR */