r600g: various fixes
[mesa.git] / src / gallium / drivers / r600 / r600_buffer.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 <MostAwesomeDude@gmail.com>
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_context.h"
35
36 extern struct u_resource_vtbl r600_buffer_vtbl;
37
38 static u32 r600_domain_from_usage(unsigned usage)
39 {
40 u32 domain = RADEON_GEM_DOMAIN_GTT;
41
42 if (usage & PIPE_BIND_RENDER_TARGET) {
43 domain |= RADEON_GEM_DOMAIN_VRAM;
44 }
45 if (usage & PIPE_BIND_DEPTH_STENCIL) {
46 domain |= RADEON_GEM_DOMAIN_VRAM;
47 }
48 if (usage & PIPE_BIND_SAMPLER_VIEW) {
49 domain |= RADEON_GEM_DOMAIN_VRAM;
50 }
51 /* also need BIND_BLIT_SOURCE/DESTINATION ? */
52 if (usage & PIPE_BIND_VERTEX_BUFFER) {
53 domain |= RADEON_GEM_DOMAIN_GTT;
54 }
55 if (usage & PIPE_BIND_INDEX_BUFFER) {
56 domain |= RADEON_GEM_DOMAIN_GTT;
57 }
58
59 return domain;
60 }
61
62 struct pipe_resource *r600_buffer_create(struct pipe_screen *screen,
63 const struct pipe_resource *templ)
64 {
65 struct r600_screen *rscreen = r600_screen(screen);
66 struct r600_buffer *rbuffer;
67 struct radeon_bo *bo;
68 struct pb_desc desc;
69 /* XXX We probably want a different alignment for buffers and textures. */
70 unsigned alignment = 4096;
71
72 rbuffer = CALLOC_STRUCT(r600_buffer);
73 if (rbuffer == NULL)
74 return NULL;
75
76 rbuffer->b.b = *templ;
77 pipe_reference_init(&rbuffer->b.b.reference, 1);
78 rbuffer->b.b.screen = screen;
79 rbuffer->b.vtbl = &r600_buffer_vtbl;
80
81 if (rbuffer->b.b.bind & PIPE_BIND_CONSTANT_BUFFER) {
82 desc.alignment = alignment;
83 desc.usage = rbuffer->b.b.bind;
84 rbuffer->pb = pb_malloc_buffer_create(rbuffer->b.b.width0,
85 &desc);
86 if (rbuffer->pb == NULL) {
87 free(rbuffer);
88 return NULL;
89 }
90 return &rbuffer->b.b;
91 }
92 rbuffer->domain = r600_domain_from_usage(rbuffer->b.b.bind);
93 bo = radeon_bo(rscreen->rw, 0, rbuffer->b.b.width0, alignment, NULL);
94 if (bo == NULL) {
95 FREE(rbuffer);
96 return NULL;
97 }
98 rbuffer->bo = bo;
99 return &rbuffer->b.b;
100 }
101
102 struct pipe_resource *r600_user_buffer_create(struct pipe_screen *screen,
103 void *ptr, unsigned bytes,
104 unsigned bind)
105 {
106 struct r600_buffer *rbuffer;
107 struct r600_screen *rscreen = r600_screen(screen);
108 struct pipe_resource templ;
109
110 memset(&templ, 0, sizeof(struct pipe_resource));
111 templ.target = PIPE_BUFFER;
112 templ.format = PIPE_FORMAT_R8_UNORM;
113 templ.usage = PIPE_USAGE_IMMUTABLE;
114 templ.bind = bind;
115 templ.width0 = bytes;
116 templ.height0 = 1;
117 templ.depth0 = 1;
118
119 rbuffer = (struct r600_buffer*)r600_buffer_create(screen, &templ);
120 if (rbuffer == NULL) {
121 return NULL;
122 }
123 radeon_bo_map(rscreen->rw, rbuffer->bo);
124 memcpy(rbuffer->bo->data, ptr, bytes);
125 radeon_bo_unmap(rscreen->rw, rbuffer->bo);
126 return &rbuffer->b.b;
127 }
128
129 static void r600_buffer_destroy(struct pipe_screen *screen,
130 struct pipe_resource *buf)
131 {
132 struct r600_buffer *rbuffer = (struct r600_buffer*)buf;
133 struct r600_screen *rscreen = r600_screen(screen);
134
135 if (rbuffer->pb) {
136 pipe_reference_init(&rbuffer->pb->base.reference, 0);
137 pb_destroy(rbuffer->pb);
138 rbuffer->pb = NULL;
139 }
140 if (rbuffer->bo) {
141 radeon_bo_decref(rscreen->rw, rbuffer->bo);
142 }
143 FREE(rbuffer);
144 }
145
146 static void *r600_buffer_transfer_map(struct pipe_context *pipe,
147 struct pipe_transfer *transfer)
148 {
149 struct r600_buffer *rbuffer = (struct r600_buffer*)transfer->resource;
150 struct r600_screen *rscreen = r600_screen(pipe->screen);
151 int write = 0;
152
153 if (rbuffer->pb) {
154 return (uint8_t*)pb_map(rbuffer->pb, transfer->usage) + transfer->box.x;
155 }
156 if (transfer->usage & PIPE_TRANSFER_DONTBLOCK) {
157 /* FIXME */
158 }
159 if (transfer->usage & PIPE_TRANSFER_WRITE) {
160 write = 1;
161 }
162 if (radeon_bo_map(rscreen->rw, rbuffer->bo)) {
163 return NULL;
164 }
165 return (uint8_t*)rbuffer->bo->data + transfer->box.x;
166 }
167
168 static void r600_buffer_transfer_unmap(struct pipe_context *pipe,
169 struct pipe_transfer *transfer)
170 {
171 struct r600_buffer *rbuffer = (struct r600_buffer*)transfer->resource;
172 struct r600_screen *rscreen = r600_screen(pipe->screen);
173
174 if (rbuffer->pb) {
175 pb_unmap(rbuffer->pb);
176 } else {
177 radeon_bo_unmap(rscreen->rw, rbuffer->bo);
178 }
179 }
180
181 static void r600_buffer_transfer_flush_region(struct pipe_context *pipe,
182 struct pipe_transfer *transfer,
183 const struct pipe_box *box)
184 {
185 }
186
187 unsigned r600_buffer_is_referenced_by_cs(struct pipe_context *context,
188 struct pipe_resource *buf,
189 unsigned face, unsigned level)
190 {
191 /* XXX */
192 return PIPE_REFERENCED_FOR_READ | PIPE_REFERENCED_FOR_WRITE;
193 }
194
195 struct pipe_resource *r600_buffer_from_handle(struct pipe_screen *screen,
196 struct winsys_handle *whandle)
197 {
198 struct radeon *rw = (struct radeon*)screen->winsys;
199 struct r600_buffer *rbuffer;
200 struct radeon_bo *bo = NULL;
201
202 bo = radeon_bo(rw, whandle->handle, 0, 0, NULL);
203 if (bo == NULL) {
204 return NULL;
205 }
206
207 rbuffer = CALLOC_STRUCT(r600_buffer);
208 if (rbuffer == NULL) {
209 radeon_bo_decref(rw, bo);
210 return NULL;
211 }
212
213 pipe_reference_init(&rbuffer->b.b.reference, 1);
214 rbuffer->b.b.target = PIPE_BUFFER;
215 rbuffer->b.b.screen = screen;
216 rbuffer->b.vtbl = &r600_buffer_vtbl;
217 rbuffer->bo = bo;
218 return &rbuffer->b.b;
219 }
220
221 struct u_resource_vtbl r600_buffer_vtbl =
222 {
223 u_default_resource_get_handle, /* get_handle */
224 r600_buffer_destroy, /* resource_destroy */
225 r600_buffer_is_referenced_by_cs, /* is_buffer_referenced */
226 u_default_get_transfer, /* get_transfer */
227 u_default_transfer_destroy, /* transfer_destroy */
228 r600_buffer_transfer_map, /* transfer_map */
229 r600_buffer_transfer_flush_region, /* transfer_flush_region */
230 r600_buffer_transfer_unmap, /* transfer_unmap */
231 u_default_transfer_inline_write /* transfer_inline_write */
232 };