Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / nvfx / nvfx_miptree.c
1 #include "pipe/p_state.h"
2 #include "pipe/p_defines.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5 #include "util/u_memory.h"
6 #include "util/u_math.h"
7 #include "util/u_staging.h"
8 #include "state_tracker/drm_driver.h"
9 #include "nouveau/nouveau_winsys.h"
10 #include "nouveau/nouveau_screen.h"
11 #include "nvfx_screen.h"
12 #include "nvfx_resource.h"
13
14 static void
15 nvfx_miptree_choose_format(struct nvfx_miptree *mt)
16 {
17         struct pipe_resource *pt = &mt->base.base;
18         unsigned uniform_pitch = 0;
19         static int no_swizzle = -1;
20         if(no_swizzle < 0)
21                 no_swizzle = debug_get_bool_option("NV40_NO_SWIZZLE", FALSE); /* this will break things on nv30 */
22
23         if (!util_is_power_of_two(pt->width0) ||
24             !util_is_power_of_two(pt->height0) ||
25             !util_is_power_of_two(pt->depth0) ||
26             (!nvfx_screen(pt->screen)->is_nv4x && pt->target == PIPE_TEXTURE_RECT)
27             )
28                 uniform_pitch = 1;
29
30         if (
31                 (pt->bind & (PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET))
32                 || (pt->usage & PIPE_USAGE_DYNAMIC) || (pt->usage & PIPE_USAGE_STAGING)
33                 || util_format_is_compressed(pt->format)
34                 || no_swizzle
35         )
36                 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
37
38         /* non compressed formats with uniform pitch must be linear, and vice versa */
39         if(!util_format_is_s3tc(pt->format)
40                 && (uniform_pitch || mt->base.base.flags & NVFX_RESOURCE_FLAG_LINEAR))
41         {
42                 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
43                 uniform_pitch = 1;
44         }
45
46         if(uniform_pitch)
47         {
48                 mt->linear_pitch = util_format_get_stride(pt->format, pt->width0);
49
50                 // TODO: this is only a constraint for rendering and not sampling, apparently
51                 // we may also want this unconditionally
52                 if(pt->bind & (PIPE_BIND_SAMPLER_VIEW |
53                         PIPE_BIND_DEPTH_STENCIL |
54                         PIPE_BIND_RENDER_TARGET |
55                         PIPE_BIND_DISPLAY_TARGET |
56                         PIPE_BIND_SCANOUT))
57                         mt->linear_pitch = align(mt->linear_pitch, 64);
58         }
59         else
60                 mt->linear_pitch = 0;
61 }
62
63 static unsigned
64 nvfx_miptree_layout(struct nvfx_miptree *mt)
65 {
66         struct pipe_resource* pt = &mt->base.base;
67         uint offset = 0;
68
69         if(!nvfx_screen(pt->screen)->is_nv4x)
70         {
71                 assert(pt->target == PIPE_TEXTURE_RECT
72                         || (util_is_power_of_two(pt->width0) && util_is_power_of_two(pt->height0)));
73         }
74
75         for (unsigned l = 0; l <= pt->last_level; l++)
76         {
77                 unsigned size;
78                 mt->level_offset[l] = offset;
79
80                 if(mt->linear_pitch)
81                         size = mt->linear_pitch;
82                 else
83                         size = util_format_get_stride(pt->format, u_minify(pt->width0, l));
84                 size = util_format_get_2d_size(pt->format, size, u_minify(pt->height0, l));
85
86                 if(pt->target == PIPE_TEXTURE_3D)
87                         size *= u_minify(pt->depth0, l);
88
89                 offset += size;
90         }
91
92         offset = align(offset, 128);
93         mt->face_size = offset;
94         if(mt->base.base.target == PIPE_TEXTURE_CUBE)
95                 offset += 5 * mt->face_size;
96         return offset;
97 }
98
99 static void
100 nvfx_miptree_surface_final_destroy(struct pipe_surface* ps)
101 {
102         struct nvfx_surface* ns = (struct nvfx_surface*)ps;
103         pipe_resource_reference(&ps->texture, 0);
104         pipe_resource_reference((struct pipe_resource**)&ns->temp, 0);
105         FREE(ps);
106 }
107
108 void
109 nvfx_miptree_destroy(struct pipe_screen *screen, struct pipe_resource *pt)
110 {
111         struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
112         util_surfaces_destroy(&mt->surfaces, pt, nvfx_miptree_surface_final_destroy);
113         nouveau_screen_bo_release(screen, mt->base.bo);
114         FREE(mt);
115 }
116
117 static struct nvfx_miptree*
118 nvfx_miptree_create_skeleton(struct pipe_screen *pscreen, const struct pipe_resource *pt)
119 {
120         struct nvfx_miptree *mt;
121
122         if(pt->width0 > 4096 || pt->height0 > 4096)
123                 return NULL;
124
125         mt = CALLOC_STRUCT(nvfx_miptree);
126         if (!mt)
127                 return NULL;
128
129         mt->base.base = *pt;
130         util_dirty_surfaces_init(&mt->dirty_surfaces);
131
132         pipe_reference_init(&mt->base.base.reference, 1);
133         mt->base.base.screen = pscreen;
134
135         // set this to the actual capabilities, we use it to decide whether to use the 3D engine for copies
136         // TODO: is this the correct way to use Gallium?
137         mt->base.base.bind = pt->bind | PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_DEPTH_STENCIL;
138
139         // on our current driver (and the driver too), format support does not depend on geometry, so don't bother computing it
140         // TODO: may want to revisit this
141         if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_RENDER_TARGET))
142                 mt->base.base.bind &=~ PIPE_BIND_RENDER_TARGET;
143         if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_SAMPLER_VIEW))
144                 mt->base.base.bind &=~ PIPE_BIND_SAMPLER_VIEW;
145         if(!pscreen->is_format_supported(pscreen, pt->format, pt->target, 0, PIPE_BIND_DEPTH_STENCIL))
146                 mt->base.base.bind &=~ PIPE_BIND_DEPTH_STENCIL;
147
148         return mt;
149 }
150
151
152 struct pipe_resource *
153 nvfx_miptree_create(struct pipe_screen *pscreen, const struct pipe_resource *pt)
154 {
155         struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, pt);
156         unsigned size;
157         nvfx_miptree_choose_format(mt);
158
159         size = nvfx_miptree_layout(mt);
160
161         mt->base.bo = nouveau_screen_bo_new(pscreen, 256, pt->usage, pt->bind, size);
162
163         if (!mt->base.bo) {
164                 FREE(mt);
165                 return NULL;
166         }
167         return &mt->base.base;
168 }
169
170 // TODO: redo this, just calling miptree_layout
171 struct pipe_resource *
172 nvfx_miptree_from_handle(struct pipe_screen *pscreen, const struct pipe_resource *template, struct winsys_handle *whandle)
173 {
174         struct nvfx_miptree* mt = nvfx_miptree_create_skeleton(pscreen, template);
175         unsigned stride;
176         if(whandle->stride) {
177                 mt->linear_pitch = whandle->stride;
178                 mt->base.base.flags |= NVFX_RESOURCE_FLAG_LINEAR;
179         } else
180                 nvfx_miptree_choose_format(mt);
181
182         nvfx_miptree_layout(mt);
183
184         mt->base.bo = nouveau_screen_bo_from_handle(pscreen, whandle, &stride);
185         if (mt->base.bo == NULL) {
186                 FREE(mt);
187                 return NULL;
188         }
189         return &mt->base.base;
190 }
191
192 struct pipe_surface *
193 nvfx_miptree_surface_new(struct pipe_context *pipe, struct pipe_resource *pt,
194                          const struct pipe_surface *surf_tmpl)
195 {
196         struct nvfx_miptree *mt = (struct nvfx_miptree *)pt;
197         unsigned level = surf_tmpl->u.tex.level;
198         struct nvfx_surface *ns = NULL;
199
200         assert(surf_tmpl->u.tex.first_layer == surf_tmpl->u.tex.last_layer);
201         if(util_surfaces_get(&mt->surfaces, sizeof(struct nvfx_surface), pipe,
202                              pt, level, surf_tmpl->u.tex.first_layer,
203                              surf_tmpl->usage, (struct pipe_surface **)&ns)) {
204                 util_dirty_surface_init(&ns->base);
205                 ns->pitch = nvfx_subresource_pitch(pt, level);
206                 ns->offset = nvfx_subresource_offset(pt, surf_tmpl->u.tex.first_layer, level, surf_tmpl->u.tex.first_layer);
207         }
208
209         return &ns->base.base;
210 }
211
212 void
213 nvfx_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
214 {
215         struct nvfx_surface* ns = (struct nvfx_surface*)ps;
216
217         if(!ns->temp)
218         {
219                 assert(!util_dirty_surface_is_dirty(&ns->base));
220                 util_surfaces_detach(&((struct nvfx_miptree*)ps->texture)->surfaces, ps);
221                 pipe_resource_reference(&ps->texture, 0);
222                 FREE(ps);
223         }
224 }