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