1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2010 Red Hat Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub
8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom
9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors: Dave Airlie
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include <stdio.h>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "util/u_inlines.h"
29bf215546Sopenharmony_ci#include "util/u_memory.h"
30bf215546Sopenharmony_ci#include "util/u_upload_mgr.h"
31bf215546Sopenharmony_ci#include "util/u_math.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "r300_screen_buffer.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_civoid r300_upload_index_buffer(struct r300_context *r300,
36bf215546Sopenharmony_ci			      struct pipe_resource **index_buffer,
37bf215546Sopenharmony_ci			      unsigned index_size, unsigned *start,
38bf215546Sopenharmony_ci			      unsigned count, const uint8_t *ptr)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci    unsigned index_offset;
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci    *index_buffer = NULL;
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci    u_upload_data(r300->uploader,
45bf215546Sopenharmony_ci                  0, count * index_size, 4,
46bf215546Sopenharmony_ci                  ptr + (*start * index_size),
47bf215546Sopenharmony_ci                  &index_offset,
48bf215546Sopenharmony_ci                  index_buffer);
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci    *start = index_offset / index_size;
51bf215546Sopenharmony_ci}
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_civoid r300_resource_destroy(struct pipe_screen *screen,
54bf215546Sopenharmony_ci                           struct pipe_resource *buf)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   if (buf->target == PIPE_BUFFER) {
57bf215546Sopenharmony_ci      struct r300_resource *rbuf = r300_resource(buf);
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci      align_free(rbuf->malloced_buffer);
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci      if (rbuf->buf)
62bf215546Sopenharmony_ci         pb_reference(&rbuf->buf, NULL);
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci      FREE(rbuf);
65bf215546Sopenharmony_ci   } else {
66bf215546Sopenharmony_ci      struct r300_screen *rscreen = r300_screen(screen);
67bf215546Sopenharmony_ci      struct r300_resource* tex = (struct r300_resource*)buf;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci      if (tex->tex.cmask_dwords) {
70bf215546Sopenharmony_ci          mtx_lock(&rscreen->cmask_mutex);
71bf215546Sopenharmony_ci          if (buf == rscreen->cmask_resource) {
72bf215546Sopenharmony_ci              rscreen->cmask_resource = NULL;
73bf215546Sopenharmony_ci          }
74bf215546Sopenharmony_ci          mtx_unlock(&rscreen->cmask_mutex);
75bf215546Sopenharmony_ci      }
76bf215546Sopenharmony_ci      pb_reference(&tex->buf, NULL);
77bf215546Sopenharmony_ci      FREE(tex);
78bf215546Sopenharmony_ci   }
79bf215546Sopenharmony_ci}
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_civoid *
82bf215546Sopenharmony_cir300_buffer_transfer_map( struct pipe_context *context,
83bf215546Sopenharmony_ci                          struct pipe_resource *resource,
84bf215546Sopenharmony_ci                          unsigned level,
85bf215546Sopenharmony_ci                          unsigned usage,
86bf215546Sopenharmony_ci                          const struct pipe_box *box,
87bf215546Sopenharmony_ci                          struct pipe_transfer **ptransfer )
88bf215546Sopenharmony_ci{
89bf215546Sopenharmony_ci    struct r300_context *r300 = r300_context(context);
90bf215546Sopenharmony_ci    struct radeon_winsys *rws = r300->screen->rws;
91bf215546Sopenharmony_ci    struct r300_resource *rbuf = r300_resource(resource);
92bf215546Sopenharmony_ci    struct pipe_transfer *transfer;
93bf215546Sopenharmony_ci    uint8_t *map;
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci    transfer = slab_alloc(&r300->pool_transfers);
96bf215546Sopenharmony_ci    transfer->resource = resource;
97bf215546Sopenharmony_ci    transfer->level = level;
98bf215546Sopenharmony_ci    transfer->usage = usage;
99bf215546Sopenharmony_ci    transfer->box = *box;
100bf215546Sopenharmony_ci    transfer->stride = 0;
101bf215546Sopenharmony_ci    transfer->layer_stride = 0;
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci    if (rbuf->malloced_buffer) {
104bf215546Sopenharmony_ci        *ptransfer = transfer;
105bf215546Sopenharmony_ci        return rbuf->malloced_buffer + box->x;
106bf215546Sopenharmony_ci    }
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci    if (usage & PIPE_MAP_DISCARD_WHOLE_RESOURCE &&
109bf215546Sopenharmony_ci        !(usage & PIPE_MAP_UNSYNCHRONIZED)) {
110bf215546Sopenharmony_ci        assert(usage & PIPE_MAP_WRITE);
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci        /* Check if mapping this buffer would cause waiting for the GPU. */
113bf215546Sopenharmony_ci        if (r300->rws->cs_is_buffer_referenced(&r300->cs, rbuf->buf, RADEON_USAGE_READWRITE) ||
114bf215546Sopenharmony_ci            !r300->rws->buffer_wait(r300->rws, rbuf->buf, 0, RADEON_USAGE_READWRITE)) {
115bf215546Sopenharmony_ci            unsigned i;
116bf215546Sopenharmony_ci            struct pb_buffer *new_buf;
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci            /* Create a new one in the same pipe_resource. */
119bf215546Sopenharmony_ci            new_buf = r300->rws->buffer_create(r300->rws, rbuf->b.width0,
120bf215546Sopenharmony_ci                                               R300_BUFFER_ALIGNMENT,
121bf215546Sopenharmony_ci                                               rbuf->domain,
122bf215546Sopenharmony_ci                                               RADEON_FLAG_NO_INTERPROCESS_SHARING);
123bf215546Sopenharmony_ci            if (new_buf) {
124bf215546Sopenharmony_ci                /* Discard the old buffer. */
125bf215546Sopenharmony_ci                pb_reference(&rbuf->buf, NULL);
126bf215546Sopenharmony_ci                rbuf->buf = new_buf;
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci                /* We changed the buffer, now we need to bind it where the old one was bound. */
129bf215546Sopenharmony_ci                for (i = 0; i < r300->nr_vertex_buffers; i++) {
130bf215546Sopenharmony_ci                    if (r300->vertex_buffer[i].buffer.resource == &rbuf->b) {
131bf215546Sopenharmony_ci                        r300->vertex_arrays_dirty = TRUE;
132bf215546Sopenharmony_ci                        break;
133bf215546Sopenharmony_ci                    }
134bf215546Sopenharmony_ci                }
135bf215546Sopenharmony_ci            }
136bf215546Sopenharmony_ci        }
137bf215546Sopenharmony_ci    }
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci    /* Buffers are never used for write, therefore mapping for read can be
140bf215546Sopenharmony_ci     * unsynchronized. */
141bf215546Sopenharmony_ci    if (!(usage & PIPE_MAP_WRITE)) {
142bf215546Sopenharmony_ci       usage |= PIPE_MAP_UNSYNCHRONIZED;
143bf215546Sopenharmony_ci    }
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci    map = rws->buffer_map(rws, rbuf->buf, &r300->cs, usage);
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci    if (!map) {
148bf215546Sopenharmony_ci        slab_free(&r300->pool_transfers, transfer);
149bf215546Sopenharmony_ci        return NULL;
150bf215546Sopenharmony_ci    }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci    *ptransfer = transfer;
153bf215546Sopenharmony_ci    return map + box->x;
154bf215546Sopenharmony_ci}
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_civoid r300_buffer_transfer_unmap( struct pipe_context *pipe,
157bf215546Sopenharmony_ci                                 struct pipe_transfer *transfer )
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci    struct r300_context *r300 = r300_context(pipe);
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci    slab_free(&r300->pool_transfers, transfer);
162bf215546Sopenharmony_ci}
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_cistruct pipe_resource *r300_buffer_create(struct pipe_screen *screen,
165bf215546Sopenharmony_ci					 const struct pipe_resource *templ)
166bf215546Sopenharmony_ci{
167bf215546Sopenharmony_ci    struct r300_screen *r300screen = r300_screen(screen);
168bf215546Sopenharmony_ci    struct r300_resource *rbuf;
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci    rbuf = MALLOC_STRUCT(r300_resource);
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci    rbuf->b = *templ;
173bf215546Sopenharmony_ci    pipe_reference_init(&rbuf->b.reference, 1);
174bf215546Sopenharmony_ci    rbuf->b.screen = screen;
175bf215546Sopenharmony_ci    rbuf->domain = RADEON_DOMAIN_GTT;
176bf215546Sopenharmony_ci    rbuf->buf = NULL;
177bf215546Sopenharmony_ci    rbuf->malloced_buffer = NULL;
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci    /* Allocate constant buffers and SWTCL vertex and index buffers in RAM.
180bf215546Sopenharmony_ci     * Note that uploaded index buffers use the flag PIPE_BIND_CUSTOM, so that
181bf215546Sopenharmony_ci     * we can distinguish them from user-created buffers.
182bf215546Sopenharmony_ci     */
183bf215546Sopenharmony_ci    if (templ->bind & PIPE_BIND_CONSTANT_BUFFER ||
184bf215546Sopenharmony_ci        (!r300screen->caps.has_tcl && !(templ->bind & PIPE_BIND_CUSTOM))) {
185bf215546Sopenharmony_ci        rbuf->malloced_buffer = align_malloc(templ->width0, 64);
186bf215546Sopenharmony_ci        return &rbuf->b;
187bf215546Sopenharmony_ci    }
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci    rbuf->buf =
190bf215546Sopenharmony_ci        r300screen->rws->buffer_create(r300screen->rws, rbuf->b.width0,
191bf215546Sopenharmony_ci                                       R300_BUFFER_ALIGNMENT,
192bf215546Sopenharmony_ci                                       rbuf->domain,
193bf215546Sopenharmony_ci                                       RADEON_FLAG_NO_INTERPROCESS_SHARING);
194bf215546Sopenharmony_ci    if (!rbuf->buf) {
195bf215546Sopenharmony_ci        FREE(rbuf);
196bf215546Sopenharmony_ci        return NULL;
197bf215546Sopenharmony_ci    }
198bf215546Sopenharmony_ci    return &rbuf->b;
199bf215546Sopenharmony_ci}
200