OSDN Git Service

intel: Add a forward declaration of struct drm_clip_rect
[android-x86/external-libdrm.git] / nouveau / nouveau_reloc.c
1 /*
2  * Copyright 2010 Nouveau Project
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 shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19  * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "nouveau_private.h"
29
30 static uint32_t
31 nouveau_reloc_calc(struct drm_nouveau_gem_pushbuf_bo *pbbo,
32                    struct drm_nouveau_gem_pushbuf_reloc *r)
33 {
34         uint32_t push = 0;
35
36         if (r->flags & NOUVEAU_GEM_RELOC_LOW)
37                 push = (pbbo->presumed.offset + r->data);
38         else
39         if (r->flags & NOUVEAU_GEM_RELOC_HIGH)
40                 push = (pbbo->presumed.offset + r->data) >> 32;
41         else
42                 push = r->data;
43
44         if (r->flags & NOUVEAU_GEM_RELOC_OR) {
45                 if (pbbo->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM)
46                         push |= r->vor;
47                 else
48                         push |= r->tor;
49         }
50
51         return push;
52 }
53
54 int
55 nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo,
56                    uint32_t reloc_offset, uint32_t *reloc_ptr,
57                    struct nouveau_bo *bo, uint32_t data, uint32_t data2,
58                    uint32_t flags, uint32_t vor, uint32_t tor)
59 {
60         struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb;
61         struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
62         struct drm_nouveau_gem_pushbuf_reloc *r;
63         struct drm_nouveau_gem_pushbuf_bo *pbbo, *rpbbo;
64         uint32_t domains = 0;
65
66         if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) {
67                 fprintf(stderr, "too many relocs!!\n");
68                 return -ENOMEM;
69         }
70
71         if (nvbo->user && (flags & NOUVEAU_BO_WR)) {
72                 fprintf(stderr, "write to user buffer!!\n");
73                 return -EINVAL;
74         }
75
76         /* We're about to reloc a user buffer, better make sure we don't cause
77          * a double migration.
78          */
79         if (!(nvbo->flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM)))
80                 nvbo->flags |= (flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM));
81
82         rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo);
83         if (!rpbbo)
84                 return -ENOMEM;
85         nouveau_bo(reloc_bo)->pending_refcnt++;
86
87         pbbo = nouveau_bo_emit_buffer(chan, bo);
88         if (!pbbo) {
89                 fprintf(stderr, "buffer emit fail :(\n");
90                 return -ENOMEM;
91         }
92         nouveau_bo(bo)->pending_refcnt++;
93
94         if (flags & NOUVEAU_BO_VRAM)
95                 domains |= NOUVEAU_GEM_DOMAIN_VRAM;
96         if (flags & NOUVEAU_BO_GART)
97                 domains |= NOUVEAU_GEM_DOMAIN_GART;
98
99         if (!(pbbo->valid_domains & domains)) {
100                 fprintf(stderr, "no valid domains remain!\n");
101                 return -EINVAL;
102         }
103         pbbo->valid_domains &= domains;
104
105         assert(flags & NOUVEAU_BO_RDWR);
106         if (flags & NOUVEAU_BO_RD) {
107                 pbbo->read_domains |= domains;
108         }
109         if (flags & NOUVEAU_BO_WR) {
110                 pbbo->write_domains |= domains;
111                 nvbo->write_marker = 1;
112         }
113
114         r = nvpb->relocs + nvpb->nr_relocs++;
115         r->reloc_bo_index = rpbbo - nvpb->buffers;
116         r->reloc_bo_offset = reloc_offset;
117         r->bo_index = pbbo - nvpb->buffers;
118         r->flags = 0;
119         if (flags & NOUVEAU_BO_LOW)
120                 r->flags |= NOUVEAU_GEM_RELOC_LOW;
121         if (flags & NOUVEAU_BO_HIGH)
122                 r->flags |= NOUVEAU_GEM_RELOC_HIGH;
123         if (flags & NOUVEAU_BO_OR)
124                 r->flags |= NOUVEAU_GEM_RELOC_OR;
125         r->data = data;
126         r->vor = vor;
127         r->tor = tor;
128
129         if (reloc_ptr) {
130                 if (flags & NOUVEAU_BO_DUMMY)
131                         *reloc_ptr = 0;
132                 else
133                         *reloc_ptr = nouveau_reloc_calc(pbbo, r);
134         }
135
136         return 0;
137 }
138