i915g: Reduce state emission by using a index bias
[mesa.git] / src / gallium / drivers / r600 / r600_texture.c
1 /*
2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 * Authors:
24 * Jerome Glisse
25 * Corbin Simpson
26 */
27 #include <pipe/p_screen.h>
28 #include <util/u_format.h>
29 #include <util/u_math.h>
30 #include <util/u_inlines.h>
31 #include <util/u_memory.h>
32 #include "state_tracker/drm_api.h"
33 #include "r600_screen.h"
34 #include "r600_texture.h"
35
36 extern struct u_resource_vtbl r600_texture_vtbl;
37
38 unsigned long r600_texture_get_offset(struct r600_texture *rtex, unsigned level, unsigned zslice, unsigned face)
39 {
40 unsigned long offset = rtex->offset[level];
41
42 switch (rtex->b.b.target) {
43 case PIPE_TEXTURE_3D:
44 assert(face == 0);
45 return offset + zslice * rtex->layer_size[level];
46 case PIPE_TEXTURE_CUBE:
47 assert(zslice == 0);
48 return offset + face * rtex->layer_size[level];
49 default:
50 assert(zslice == 0 && face == 0);
51 return offset;
52 }
53 }
54
55 static void r600_setup_miptree(struct r600_screen *rscreen, struct r600_texture *rtex)
56 {
57 struct pipe_resource *ptex = &rtex->b.b;
58 unsigned long w, h, stride, size, layer_size, i, offset;
59
60 for (i = 0, offset = 0; i <= ptex->last_level; i++) {
61 w = u_minify(ptex->width0, i);
62 h = u_minify(ptex->height0, i);
63 stride = align(util_format_get_stride(ptex->format, w), 32);
64 layer_size = stride * h;
65 if (ptex->target == PIPE_TEXTURE_CUBE)
66 size = layer_size * 6;
67 else
68 size = layer_size * u_minify(ptex->depth0, i);
69 rtex->offset[i] = offset;
70 rtex->layer_size[i] = layer_size;
71 rtex->pitch[i] = stride / util_format_get_blocksize(ptex->format);
72 rtex->stride[i] = stride;
73 offset += align(size, 32);
74 }
75 rtex->size = offset;
76 }
77
78 struct pipe_resource *r600_texture_create(struct pipe_screen *screen,
79 const struct pipe_resource *templ)
80 {
81 struct r600_texture *rtex = CALLOC_STRUCT(r600_texture);
82 struct r600_screen *rscreen = r600_screen(screen);
83 struct pipe_resource templ_buf;
84
85 if (!rtex) {
86 return NULL;
87 }
88 rtex->b.b = *templ;
89 rtex->b.vtbl = &r600_texture_vtbl;
90 pipe_reference_init(&rtex->b.b.reference, 1);
91 rtex->b.b.screen = screen;
92 r600_setup_miptree(rscreen, rtex);
93
94 memset(&templ_buf, 0, sizeof(struct pipe_resource));
95 templ_buf.target = PIPE_BUFFER;
96 templ_buf.format = PIPE_FORMAT_R8_UNORM;
97 templ_buf.usage = templ->usage;
98 templ_buf.bind = templ->bind;
99 templ_buf.width0 = rtex->size;
100 templ_buf.height0 = 1;
101 templ_buf.depth0 = 1;
102
103 rtex->buffer = screen->resource_create(screen, &templ_buf);
104 if (!rtex->buffer) {
105 FREE(rtex);
106 return NULL;
107 }
108 return &rtex->b.b;
109 }
110
111 static void r600_texture_destroy(struct pipe_screen *screen,
112 struct pipe_resource *ptex)
113 {
114 struct r600_texture *rtex = (struct r600_texture*)ptex;
115
116 FREE(rtex);
117 }
118
119 static struct pipe_surface *r600_get_tex_surface(struct pipe_screen *screen,
120 struct pipe_resource *texture,
121 unsigned face, unsigned level,
122 unsigned zslice, unsigned flags)
123 {
124 struct r600_texture *rtex = (struct r600_texture*)texture;
125 struct pipe_surface *surface = CALLOC_STRUCT(pipe_surface);
126 unsigned long offset;
127
128 if (surface == NULL)
129 return NULL;
130 offset = r600_texture_get_offset(rtex, level, zslice, face);
131 pipe_reference_init(&surface->reference, 1);
132 pipe_resource_reference(&surface->texture, texture);
133 surface->format = texture->format;
134 surface->width = u_minify(texture->width0, level);
135 surface->height = u_minify(texture->height0, level);
136 surface->offset = offset;
137 surface->usage = flags;
138 surface->zslice = zslice;
139 surface->texture = texture;
140 surface->face = face;
141 surface->level = level;
142 return surface;
143 }
144
145 static void r600_tex_surface_destroy(struct pipe_surface *surface)
146 {
147 pipe_resource_reference(&surface->texture, NULL);
148 FREE(surface);
149 }
150
151 struct pipe_resource *r600_texture_from_handle(struct pipe_screen *screen,
152 const struct pipe_resource *base,
153 struct winsys_handle *whandle)
154 {
155 struct pipe_resource *buffer;
156 struct r600_texture *rtex;
157
158 buffer = r600_buffer_from_handle(screen, whandle);
159 if (buffer == NULL) {
160 return NULL;
161 }
162
163 /* Support only 2D textures without mipmaps */
164 if (base->target != PIPE_TEXTURE_2D || base->depth0 != 1 || base->last_level != 0)
165 return NULL;
166
167 rtex = CALLOC_STRUCT(r600_texture);
168 if (rtex == NULL)
169 return NULL;
170
171 /* one ref already taken */
172 rtex->buffer = buffer;
173
174 rtex->b.b = *base;
175 rtex->b.vtbl = &r600_texture_vtbl;
176 pipe_reference_init(&rtex->b.b.reference, 1);
177 rtex->b.b.screen = screen;
178 rtex->stride_override = whandle->stride;
179 rtex->pitch[0] = whandle->stride / util_format_get_blocksize(base->format);
180 rtex->stride[0] = whandle->stride;
181 rtex->offset[0] = 0;
182 rtex->size = align(rtex->stride[0] * base->height0, 32);
183
184 return &rtex->b.b;
185 }
186
187 static boolean r600_texture_get_handle(struct pipe_screen* screen,
188 struct pipe_resource *texture,
189 struct winsys_handle *whandle)
190 {
191 struct r600_screen *rscreen = r600_screen(screen);
192 struct r600_texture* rtex = (struct r600_texture*)texture;
193
194 if (!rtex) {
195 return FALSE;
196 }
197
198 whandle->stride = rtex->stride[0];
199
200 r600_buffer_get_handle(rscreen->rw, rtex->buffer, whandle);
201
202 return TRUE;
203 }
204
205 static unsigned int r600_texture_is_referenced(struct pipe_context *context,
206 struct pipe_resource *texture,
207 unsigned face, unsigned level)
208 {
209 struct r600_texture *rtex = (struct r600_texture*)texture;
210
211 return r600_buffer_is_referenced_by_cs(context, rtex->buffer, face, level);
212 }
213
214 struct u_resource_vtbl r600_texture_vtbl =
215 {
216 r600_texture_get_handle, /* get_handle */
217 r600_texture_destroy, /* resource_destroy */
218 r600_texture_is_referenced, /* is_resource_referenced */
219 r600_texture_get_transfer, /* get_transfer */
220 r600_texture_transfer_destroy, /* transfer_destroy */
221 r600_texture_transfer_map, /* transfer_map */
222 u_default_transfer_flush_region,/* transfer_flush_region */
223 r600_texture_transfer_unmap, /* transfer_unmap */
224 u_default_transfer_inline_write /* transfer_inline_write */
225 };
226
227 void r600_init_screen_texture_functions(struct pipe_screen *screen)
228 {
229 screen->get_tex_surface = r600_get_tex_surface;
230 screen->tex_surface_destroy = r600_tex_surface_destroy;
231 }