Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Copyright 2011 Joakim Sindholt |
||
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 "c99_alloca.h" |
||
24 | |||
25 | #include "device9.h" |
||
26 | #include "surface9.h" |
||
27 | #include "texture9.h" |
||
28 | #include "nine_helpers.h" |
||
29 | #include "nine_pipe.h" |
||
30 | #include "nine_dump.h" |
||
31 | |||
32 | #include "pipe/p_state.h" |
||
33 | #include "pipe/p_context.h" |
||
34 | #include "pipe/p_screen.h" |
||
35 | #include "util/u_inlines.h" |
||
36 | #include "util/u_resource.h" |
||
37 | |||
38 | #define DBG_CHANNEL DBG_TEXTURE |
||
39 | |||
40 | static HRESULT |
||
41 | NineTexture9_ctor( struct NineTexture9 *This, |
||
42 | struct NineUnknownParams *pParams, |
||
43 | UINT Width, UINT Height, UINT Levels, |
||
44 | DWORD Usage, |
||
45 | D3DFORMAT Format, |
||
46 | D3DPOOL Pool, |
||
47 | HANDLE *pSharedHandle ) |
||
48 | { |
||
49 | struct pipe_screen *screen = pParams->device->screen; |
||
50 | struct pipe_resource *info = &This->base.base.info; |
||
51 | struct pipe_resource *resource; |
||
52 | enum pipe_format pf; |
||
53 | unsigned *level_offsets; |
||
54 | unsigned l; |
||
55 | D3DSURFACE_DESC sfdesc; |
||
56 | HRESULT hr; |
||
57 | void *user_buffer = NULL, *user_buffer_for_level; |
||
58 | |||
59 | DBG("(%p) Width=%u Height=%u Levels=%u Usage=%s Format=%s Pool=%s " |
||
60 | "pSharedHandle=%p\n", This, Width, Height, Levels, |
||
61 | nine_D3DUSAGE_to_str(Usage), |
||
62 | d3dformat_to_string(Format), nine_D3DPOOL_to_str(Pool), pSharedHandle); |
||
63 | |||
64 | user_assert(!(Usage & D3DUSAGE_AUTOGENMIPMAP) || |
||
65 | (Pool != D3DPOOL_SYSTEMMEM && Levels <= 1), D3DERR_INVALIDCALL); |
||
66 | |||
67 | /* TODO: implement buffer sharing (should work with cross process too) |
||
68 | * |
||
69 | * Gem names may have fit but they're depreciated and won't work on render-nodes. |
||
70 | * One solution is to use shm buffers. We would use a /dev/shm file, fill the first |
||
71 | * values to tell it is a nine buffer, the size, which function created it, etc, |
||
72 | * and then it would contain the data. The handle would be a number, corresponding to |
||
73 | * the file to read (/dev/shm/nine-share-4 for example would be 4). |
||
74 | * |
||
75 | * Wine just ignores the argument, which works only if the app creates the handle |
||
76 | * and won't use it. Instead of failing, we support that situation by putting an |
||
77 | * invalid handle, that we would fail to import. Please note that we don't advertise |
||
78 | * the flag indicating the support for that feature, but apps seem to not care. |
||
79 | */ |
||
80 | user_assert(!pSharedHandle || |
||
81 | Pool == D3DPOOL_SYSTEMMEM || |
||
82 | Pool == D3DPOOL_DEFAULT, D3DERR_INVALIDCALL); |
||
83 | |||
84 | if (pSharedHandle && Pool == D3DPOOL_DEFAULT) { |
||
85 | if (!*pSharedHandle) { |
||
86 | DBG("Creating Texture with invalid handle. Importing will fail\n."); |
||
87 | *pSharedHandle = (HANDLE)1; /* Wine would keep it NULL */ |
||
88 | pSharedHandle = NULL; |
||
89 | } else { |
||
90 | ERR("Application tries to use cross-process sharing feature. Nine " |
||
91 | "doesn't support it"); |
||
92 | return D3DERR_INVALIDCALL; |
||
93 | } |
||
94 | } |
||
95 | |||
96 | if (Usage & D3DUSAGE_AUTOGENMIPMAP) |
||
97 | Levels = 0; |
||
98 | |||
99 | pf = d3d9_to_pipe_format_checked(screen, Format, PIPE_TEXTURE_2D, 0, |
||
100 | PIPE_BIND_SAMPLER_VIEW, FALSE); |
||
101 | if (Format != D3DFMT_NULL && pf == PIPE_FORMAT_NONE) |
||
102 | return D3DERR_INVALIDCALL; |
||
103 | |||
104 | info->screen = screen; |
||
105 | info->target = PIPE_TEXTURE_2D; |
||
106 | info->format = pf; |
||
107 | info->width0 = Width; |
||
108 | info->height0 = Height; |
||
109 | info->depth0 = 1; |
||
110 | if (Levels) |
||
111 | info->last_level = Levels - 1; |
||
112 | else |
||
113 | info->last_level = util_logbase2(MAX2(Width, Height)); |
||
114 | info->array_size = 1; |
||
115 | info->nr_samples = 0; |
||
116 | info->bind = PIPE_BIND_SAMPLER_VIEW; |
||
117 | info->usage = PIPE_USAGE_DEFAULT; |
||
118 | info->flags = 0; |
||
119 | |||
120 | if (Usage & D3DUSAGE_RENDERTARGET) |
||
121 | info->bind |= PIPE_BIND_RENDER_TARGET; |
||
122 | if (Usage & D3DUSAGE_DEPTHSTENCIL) |
||
123 | info->bind |= PIPE_BIND_DEPTH_STENCIL; |
||
124 | |||
125 | if (Usage & D3DUSAGE_DYNAMIC) { |
||
126 | info->usage = PIPE_USAGE_DYNAMIC; |
||
127 | info->bind |= |
||
128 | PIPE_BIND_TRANSFER_READ | |
||
129 | PIPE_BIND_TRANSFER_WRITE; |
||
130 | } |
||
131 | |||
132 | if (Usage & D3DUSAGE_SOFTWAREPROCESSING) |
||
133 | DBG("Application asked for Software Vertex Processing, " |
||
134 | "but this is unimplemented\n"); |
||
135 | |||
136 | if (pSharedHandle) |
||
137 | info->bind |= PIPE_BIND_SHARED; |
||
138 | |||
139 | if (Pool == D3DPOOL_SYSTEMMEM) |
||
140 | info->usage = PIPE_USAGE_STAGING; |
||
141 | |||
142 | if (pSharedHandle && *pSharedHandle) { /* Pool == D3DPOOL_SYSTEMMEM */ |
||
143 | user_buffer = (void *)*pSharedHandle; |
||
144 | level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1)); |
||
145 | (void) nine_format_get_size_and_offsets(pf, level_offsets, |
||
146 | Width, Height, |
||
147 | info->last_level); |
||
148 | } else if (Pool != D3DPOOL_DEFAULT) { |
||
149 | /* TODO: For D3DUSAGE_AUTOGENMIPMAP, it is likely we only have to |
||
150 | * allocate only for the first level, since it is the only lockable |
||
151 | * level. Check apps don't crash if we allocate smaller buffer (some |
||
152 | * apps access sublevels of texture even if they locked only first |
||
153 | * level) */ |
||
154 | level_offsets = alloca(sizeof(unsigned) * (info->last_level + 1)); |
||
155 | user_buffer = MALLOC( |
||
156 | nine_format_get_size_and_offsets(pf, level_offsets, |
||
157 | Width, Height, |
||
158 | info->last_level)); |
||
159 | This->managed_buffer = user_buffer; |
||
160 | if (!This->managed_buffer) |
||
161 | return E_OUTOFMEMORY; |
||
162 | } |
||
163 | |||
164 | This->surfaces = CALLOC(info->last_level + 1, sizeof(*This->surfaces)); |
||
165 | if (!This->surfaces) |
||
166 | return E_OUTOFMEMORY; |
||
167 | |||
168 | hr = NineBaseTexture9_ctor(&This->base, pParams, NULL, D3DRTYPE_TEXTURE, Format, Pool, Usage); |
||
169 | if (FAILED(hr)) |
||
170 | return hr; |
||
171 | This->base.pstype = (Height == 1) ? 1 : 0; |
||
172 | |||
173 | /* Create all the surfaces right away. |
||
174 | * They manage backing storage, and transfers (LockRect) are deferred |
||
175 | * to them. |
||
176 | */ |
||
177 | sfdesc.Format = Format; |
||
178 | sfdesc.Type = D3DRTYPE_SURFACE; |
||
179 | sfdesc.Usage = Usage; |
||
180 | sfdesc.Pool = Pool; |
||
181 | sfdesc.MultiSampleType = D3DMULTISAMPLE_NONE; |
||
182 | sfdesc.MultiSampleQuality = 0; |
||
183 | |||
184 | if (Pool == D3DPOOL_SYSTEMMEM) |
||
185 | resource = NULL; |
||
186 | else |
||
187 | resource = This->base.base.resource; |
||
188 | |||
189 | for (l = 0; l <= info->last_level; ++l) { |
||
190 | sfdesc.Width = u_minify(Width, l); |
||
191 | sfdesc.Height = u_minify(Height, l); |
||
192 | /* Some apps expect the memory to be allocated in |
||
193 | * continous blocks */ |
||
194 | user_buffer_for_level = user_buffer ? user_buffer + |
||
195 | level_offsets[l] : NULL; |
||
196 | |||
197 | hr = NineSurface9_new(This->base.base.base.device, NineUnknown(This), |
||
198 | resource, user_buffer_for_level, |
||
199 | D3DRTYPE_TEXTURE, l, 0, |
||
200 | &sfdesc, &This->surfaces[l]); |
||
201 | if (FAILED(hr)) |
||
202 | return hr; |
||
203 | } |
||
204 | |||
205 | This->dirty_rect.depth = 1; /* widht == 0 means empty, depth stays 1 */ |
||
206 | |||
207 | if (pSharedHandle && !*pSharedHandle) {/* Pool == D3DPOOL_SYSTEMMEM */ |
||
208 | *pSharedHandle = This->surfaces[0]->data; |
||
209 | } |
||
210 | |||
211 | return D3D_OK; |
||
212 | } |
||
213 | |||
214 | static void |
||
215 | NineTexture9_dtor( struct NineTexture9 *This ) |
||
216 | { |
||
217 | unsigned l; |
||
218 | |||
219 | if (This->surfaces) { |
||
220 | /* The surfaces should have 0 references and be unbound now. */ |
||
221 | for (l = 0; l <= This->base.base.info.last_level; ++l) |
||
222 | NineUnknown_Destroy(&This->surfaces[l]->base.base); |
||
223 | FREE(This->surfaces); |
||
224 | } |
||
225 | |||
226 | if (This->managed_buffer) |
||
227 | FREE(This->managed_buffer); |
||
228 | |||
229 | NineBaseTexture9_dtor(&This->base); |
||
230 | } |
||
231 | |||
232 | HRESULT WINAPI |
||
233 | NineTexture9_GetLevelDesc( struct NineTexture9 *This, |
||
234 | UINT Level, |
||
235 | D3DSURFACE_DESC *pDesc ) |
||
236 | { |
||
237 | user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); |
||
238 | user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), |
||
239 | D3DERR_INVALIDCALL); |
||
240 | |||
241 | *pDesc = This->surfaces[Level]->desc; |
||
242 | |||
243 | return D3D_OK; |
||
244 | } |
||
245 | |||
246 | HRESULT WINAPI |
||
247 | NineTexture9_GetSurfaceLevel( struct NineTexture9 *This, |
||
248 | UINT Level, |
||
249 | IDirect3DSurface9 **ppSurfaceLevel ) |
||
250 | { |
||
251 | user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); |
||
252 | user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), |
||
253 | D3DERR_INVALIDCALL); |
||
254 | |||
255 | NineUnknown_AddRef(NineUnknown(This->surfaces[Level])); |
||
256 | *ppSurfaceLevel = (IDirect3DSurface9 *)This->surfaces[Level]; |
||
257 | |||
258 | return D3D_OK; |
||
259 | } |
||
260 | |||
261 | HRESULT WINAPI |
||
262 | NineTexture9_LockRect( struct NineTexture9 *This, |
||
263 | UINT Level, |
||
264 | D3DLOCKED_RECT *pLockedRect, |
||
265 | const RECT *pRect, |
||
266 | DWORD Flags ) |
||
267 | { |
||
268 | DBG("This=%p Level=%u pLockedRect=%p pRect=%p Flags=%d\n", |
||
269 | This, Level, pLockedRect, pRect, Flags); |
||
270 | |||
271 | user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); |
||
272 | user_assert(Level == 0 || !(This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP), |
||
273 | D3DERR_INVALIDCALL); |
||
274 | |||
275 | return NineSurface9_LockRect(This->surfaces[Level], pLockedRect, |
||
276 | pRect, Flags); |
||
277 | } |
||
278 | |||
279 | HRESULT WINAPI |
||
280 | NineTexture9_UnlockRect( struct NineTexture9 *This, |
||
281 | UINT Level ) |
||
282 | { |
||
283 | DBG("This=%p Level=%u\n", This, Level); |
||
284 | |||
285 | user_assert(Level <= This->base.base.info.last_level, D3DERR_INVALIDCALL); |
||
286 | |||
287 | return NineSurface9_UnlockRect(This->surfaces[Level]); |
||
288 | } |
||
289 | |||
290 | HRESULT WINAPI |
||
291 | NineTexture9_AddDirtyRect( struct NineTexture9 *This, |
||
292 | const RECT *pDirtyRect ) |
||
293 | { |
||
294 | DBG("This=%p pDirtyRect=%p[(%u,%u)-(%u,%u)]\n", This, pDirtyRect, |
||
295 | pDirtyRect ? pDirtyRect->left : 0, pDirtyRect ? pDirtyRect->top : 0, |
||
296 | pDirtyRect ? pDirtyRect->right : 0, pDirtyRect ? pDirtyRect->bottom : 0); |
||
297 | |||
298 | /* Tracking dirty regions on DEFAULT or SYSTEMMEM resources is pointless, |
||
299 | * because we always write to the final storage. Just marked it dirty in |
||
300 | * case we need to generate mip maps. |
||
301 | */ |
||
302 | if (This->base.base.pool != D3DPOOL_MANAGED) { |
||
303 | if (This->base.base.usage & D3DUSAGE_AUTOGENMIPMAP) |
||
304 | This->base.dirty_mip = TRUE; |
||
305 | return D3D_OK; |
||
306 | } |
||
307 | This->base.managed.dirty = TRUE; |
||
308 | |||
309 | BASETEX_REGISTER_UPDATE(&This->base); |
||
310 | |||
311 | if (!pDirtyRect) { |
||
312 | u_box_origin_2d(This->base.base.info.width0, |
||
313 | This->base.base.info.height0, &This->dirty_rect); |
||
314 | } else { |
||
315 | struct pipe_box box; |
||
316 | rect_to_pipe_box_clamp(&box, pDirtyRect); |
||
317 | u_box_union_2d(&This->dirty_rect, &This->dirty_rect, &box); |
||
318 | (void) u_box_clip_2d(&This->dirty_rect, &This->dirty_rect, |
||
319 | This->base.base.info.width0, |
||
320 | This->base.base.info.height0); |
||
321 | } |
||
322 | return D3D_OK; |
||
323 | } |
||
324 | |||
325 | IDirect3DTexture9Vtbl NineTexture9_vtable = { |
||
326 | (void *)NineUnknown_QueryInterface, |
||
327 | (void *)NineUnknown_AddRef, |
||
328 | (void *)NineUnknown_Release, |
||
329 | (void *)NineUnknown_GetDevice, /* actually part of Resource9 iface */ |
||
330 | (void *)NineResource9_SetPrivateData, |
||
331 | (void *)NineResource9_GetPrivateData, |
||
332 | (void *)NineResource9_FreePrivateData, |
||
333 | (void *)NineResource9_SetPriority, |
||
334 | (void *)NineResource9_GetPriority, |
||
335 | (void *)NineBaseTexture9_PreLoad, |
||
336 | (void *)NineResource9_GetType, |
||
337 | (void *)NineBaseTexture9_SetLOD, |
||
338 | (void *)NineBaseTexture9_GetLOD, |
||
339 | (void *)NineBaseTexture9_GetLevelCount, |
||
340 | (void *)NineBaseTexture9_SetAutoGenFilterType, |
||
341 | (void *)NineBaseTexture9_GetAutoGenFilterType, |
||
342 | (void *)NineBaseTexture9_GenerateMipSubLevels, |
||
343 | (void *)NineTexture9_GetLevelDesc, |
||
344 | (void *)NineTexture9_GetSurfaceLevel, |
||
345 | (void *)NineTexture9_LockRect, |
||
346 | (void *)NineTexture9_UnlockRect, |
||
347 | (void *)NineTexture9_AddDirtyRect |
||
348 | }; |
||
349 | |||
350 | static const GUID *NineTexture9_IIDs[] = { |
||
351 | &IID_IDirect3DTexture9, |
||
352 | &IID_IDirect3DBaseTexture9, |
||
353 | &IID_IDirect3DResource9, |
||
354 | &IID_IUnknown, |
||
355 | NULL |
||
356 | }; |
||
357 | |||
358 | HRESULT |
||
359 | NineTexture9_new( struct NineDevice9 *pDevice, |
||
360 | UINT Width, UINT Height, UINT Levels, |
||
361 | DWORD Usage, |
||
362 | D3DFORMAT Format, |
||
363 | D3DPOOL Pool, |
||
364 | struct NineTexture9 **ppOut, |
||
365 | HANDLE *pSharedHandle ) |
||
366 | { |
||
367 | NINE_DEVICE_CHILD_NEW(Texture9, ppOut, pDevice, |
||
368 | Width, Height, Levels, |
||
369 | Usage, Format, Pool, pSharedHandle); |
||
370 | }=>=>=>=>=>=>=> |