st/nine: Refactor how user constbufs sizes are calculated
[mesa.git] / src / gallium / state_trackers / nine / resource9.c
1 /*
2 * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
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 #include "resource9.h"
24 #include "device9.h"
25 #include "nine_helpers.h"
26 #include "nine_defines.h"
27
28 #include "pipe/p_screen.h"
29
30 #include "util/u_hash_table.h"
31 #include "util/u_inlines.h"
32
33 #include "nine_pdata.h"
34
35 #define DBG_CHANNEL DBG_RESOURCE
36
37
38 HRESULT
39 NineResource9_ctor( struct NineResource9 *This,
40 struct NineUnknownParams *pParams,
41 struct pipe_resource *initResource,
42 BOOL Allocate,
43 D3DRESOURCETYPE Type,
44 D3DPOOL Pool,
45 DWORD Usage)
46 {
47 struct pipe_screen *screen;
48 HRESULT hr;
49
50 DBG("This=%p pParams=%p initResource=%p Allocate=%d "
51 "Type=%d Pool=%d Usage=%d\n",
52 This, pParams, initResource, (int) Allocate,
53 Type, Pool, Usage);
54
55 DBG("This=%p pParams=%p initResource=%p Allocate=%d Type=%d Pool=%d usage=%d\n",
56 This, pParams, initResource, Allocate, Type, Pool, Usage);
57
58 hr = NineUnknown_ctor(&This->base, pParams);
59 if (FAILED(hr))
60 return hr;
61
62 This->info.screen = screen = This->base.device->screen;
63 if (initResource)
64 pipe_resource_reference(&This->resource, initResource);
65
66 if (Allocate) {
67 assert(!initResource);
68 DBG("(%p) Creating pipe_resource.\n", This);
69 This->resource = screen->resource_create(screen, &This->info);
70 if (!This->resource)
71 return D3DERR_OUTOFVIDEOMEMORY;
72 }
73
74 This->type = Type;
75 This->pool = Pool;
76 This->usage = Usage;
77 This->priority = 0;
78
79 This->pdata = util_hash_table_create(ht_guid_hash, ht_guid_compare);
80 if (!This->pdata)
81 return E_OUTOFMEMORY;
82
83 return D3D_OK;
84 }
85
86 void
87 NineResource9_dtor( struct NineResource9 *This )
88 {
89 if (This->pdata) {
90 util_hash_table_foreach(This->pdata, ht_guid_delete, NULL);
91 util_hash_table_destroy(This->pdata);
92 }
93
94 /* NOTE: We do have to use refcounting, the driver might
95 * still hold a reference. */
96 pipe_resource_reference(&This->resource, NULL);
97
98 NineUnknown_dtor(&This->base);
99 }
100
101 struct pipe_resource *
102 NineResource9_GetResource( struct NineResource9 *This )
103 {
104 return This->resource;
105 }
106
107 D3DPOOL
108 NineResource9_GetPool( struct NineResource9 *This )
109 {
110 return This->pool;
111 }
112
113 HRESULT WINAPI
114 NineResource9_SetPrivateData( struct NineResource9 *This,
115 REFGUID refguid,
116 const void *pData,
117 DWORD SizeOfData,
118 DWORD Flags )
119 {
120 enum pipe_error err;
121 struct pheader *header;
122 const void *user_data = pData;
123
124 DBG("This=%p refguid=%p pData=%p SizeOfData=%u Flags=%x\n",
125 This, refguid, pData, SizeOfData, Flags);
126
127 if (Flags & D3DSPD_IUNKNOWN)
128 user_assert(SizeOfData == sizeof(IUnknown *), D3DERR_INVALIDCALL);
129
130 /* data consists of a header and the actual data. avoiding 2 mallocs */
131 header = CALLOC_VARIANT_LENGTH_STRUCT(pheader, SizeOfData-1);
132 if (!header) { return E_OUTOFMEMORY; }
133 header->unknown = (Flags & D3DSPD_IUNKNOWN) ? TRUE : FALSE;
134
135 /* if the refguid already exists, delete it */
136 NineResource9_FreePrivateData(This, refguid);
137
138 /* IUnknown special case */
139 if (header->unknown) {
140 /* here the pointer doesn't point to the data we want, so point at the
141 * pointer making what we eventually copy is the pointer itself */
142 user_data = &pData;
143 }
144
145 header->size = SizeOfData;
146 memcpy(header->data, user_data, header->size);
147
148 err = util_hash_table_set(This->pdata, refguid, header);
149 if (err == PIPE_OK) {
150 if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); }
151 return D3D_OK;
152 }
153
154 FREE(header);
155 if (err == PIPE_ERROR_OUT_OF_MEMORY) { return E_OUTOFMEMORY; }
156
157 return D3DERR_DRIVERINTERNALERROR;
158 }
159
160 HRESULT WINAPI
161 NineResource9_GetPrivateData( struct NineResource9 *This,
162 REFGUID refguid,
163 void *pData,
164 DWORD *pSizeOfData )
165 {
166 struct pheader *header;
167
168 DBG("This=%p refguid=%p pData=%p pSizeOfData=%p\n",
169 This, refguid, pData, pSizeOfData);
170
171 user_assert(pSizeOfData, E_POINTER);
172
173 header = util_hash_table_get(This->pdata, refguid);
174 if (!header) { return D3DERR_NOTFOUND; }
175
176 if (!pData) {
177 *pSizeOfData = header->size;
178 return D3D_OK;
179 }
180 if (*pSizeOfData < header->size) {
181 return D3DERR_MOREDATA;
182 }
183
184 if (header->unknown) { IUnknown_AddRef(*(IUnknown **)header->data); }
185 memcpy(pData, header->data, header->size);
186
187 return D3D_OK;
188 }
189
190 HRESULT WINAPI
191 NineResource9_FreePrivateData( struct NineResource9 *This,
192 REFGUID refguid )
193 {
194 struct pheader *header;
195
196 DBG("This=%p refguid=%p\n", This, refguid);
197
198 header = util_hash_table_get(This->pdata, refguid);
199 if (!header)
200 return D3DERR_NOTFOUND;
201
202 ht_guid_delete(NULL, header, NULL);
203 util_hash_table_remove(This->pdata, refguid);
204
205 return D3D_OK;
206 }
207
208 DWORD WINAPI
209 NineResource9_SetPriority( struct NineResource9 *This,
210 DWORD PriorityNew )
211 {
212 DWORD prev = This->priority;
213
214 DBG("This=%p, PriorityNew=%d\n", This, PriorityNew);
215
216 This->priority = PriorityNew;
217 return prev;
218 }
219
220 DWORD WINAPI
221 NineResource9_GetPriority( struct NineResource9 *This )
222 {
223 return This->priority;
224 }
225
226 /* NOTE: Don't forget to adjust locked vtable if you change this ! */
227 void WINAPI
228 NineResource9_PreLoad( struct NineResource9 *This )
229 {
230 if (This->pool != D3DPOOL_MANAGED)
231 return;
232 /* We don't treat managed vertex or index buffers different from
233 * default ones (are managed vertex buffers even allowed ?), and
234 * the PreLoad for textures is overridden by superclass.
235 */
236 }
237
238 D3DRESOURCETYPE WINAPI
239 NineResource9_GetType( struct NineResource9 *This )
240 {
241 return This->type;
242 }