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