wined3d: Remove IWineD3DResource::UnLoad() from the public interface.
[wine] / dlls / wined3d / cubetexture.c
1 /*
2  * IWineD3DCubeTexture implementation
3  *
4  * Copyright 2002-2005 Jason Edmeades
5  * Copyright 2002-2005 Raphael Junqueira
6  * Copyright 2005 Oliver Stieber
7  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
8  * Copyright 2009-2010 Henri Verbeet for CodeWeavers
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_texture);
29
30 /* Context activation is done by the caller. */
31 static HRESULT cubetexture_bind(IWineD3DBaseTextureImpl *texture, BOOL srgb)
32 {
33     BOOL set_gl_texture_desc;
34     HRESULT hr;
35
36     TRACE("texture %p, srgb %#x.\n", texture, srgb);
37
38     hr = basetexture_bind(texture, srgb, &set_gl_texture_desc);
39     if (set_gl_texture_desc && SUCCEEDED(hr))
40     {
41         UINT sub_count = texture->baseTexture.level_count * texture->baseTexture.layer_count;
42         UINT i;
43
44         for (i = 0; i < sub_count; ++i)
45         {
46             IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)texture->baseTexture.sub_resources[i];
47
48             if (texture->baseTexture.is_srgb)
49                 surface_set_texture_name(surface, texture->baseTexture.texture_srgb.name, TRUE);
50             else
51                 surface_set_texture_name(surface, texture->baseTexture.texture_rgb.name, FALSE);
52         }
53     }
54
55     return hr;
56 }
57
58 /* Do not call while under the GL lock. */
59 static void cubetexture_preload(IWineD3DBaseTextureImpl *texture, enum WINED3DSRGB srgb)
60 {
61     UINT sub_count = texture->baseTexture.level_count * texture->baseTexture.layer_count;
62     IWineD3DDeviceImpl *device = texture->resource.device;
63     struct wined3d_context *context = NULL;
64     BOOL srgb_mode;
65     BOOL *dirty;
66     UINT i;
67
68     TRACE("texture %p, srgb %#x.\n", texture, srgb);
69
70     switch (srgb)
71     {
72         case SRGB_RGB:
73             srgb_mode = FALSE;
74             break;
75
76         case SRGB_BOTH:
77             cubetexture_preload(texture, SRGB_RGB);
78             /* Fallthrough */
79
80         case SRGB_SRGB:
81             srgb_mode = TRUE;
82             break;
83
84         default:
85             srgb_mode = texture->baseTexture.is_srgb;
86             break;
87     }
88     dirty = srgb_mode ? &texture->baseTexture.texture_srgb.dirty : &texture->baseTexture.texture_rgb.dirty;
89
90     /* We only have to activate a context for gl when we're not drawing.
91      * In most cases PreLoad will be called during draw and a context was
92      * activated at the beginning of drawPrimitive. */
93     if (!device->isInDraw)
94     {
95         /* No danger of recursive calls, context_acquire() sets isInDraw to true
96          * when loading offscreen render targets into their texture. */
97         context = context_acquire(device, NULL);
98     }
99
100     if (texture->resource.format->id == WINED3DFMT_P8_UINT
101             || texture->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
102     {
103         for (i = 0; i < sub_count; ++i)
104         {
105             IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)texture->baseTexture.sub_resources[i];
106
107             if (palette9_changed(surface))
108             {
109                 TRACE("Reloading surface %p because the d3d8/9 palette was changed.\n", surface);
110                 /* TODO: This is not necessarily needed with hw palettized texture support. */
111                 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
112                 /* Make sure the texture is reloaded because of the palette change,
113                  * this kills performance though :( */
114                 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
115             }
116         }
117     }
118
119     /* If the texture is marked dirty or the srgb sampler setting has changed
120      * since the last load then reload the surfaces. */
121     if (*dirty)
122     {
123         for (i = 0; i < sub_count; ++i)
124         {
125             surface_load((IWineD3DSurfaceImpl *)texture->baseTexture.sub_resources[i], srgb_mode);
126         }
127     }
128     else
129     {
130         TRACE("Texture %p not dirty, nothing to do.\n" , texture);
131     }
132
133     /* No longer dirty. */
134     *dirty = FALSE;
135
136     if (context) context_release(context);
137 }
138
139 /* Do not call while under the GL lock. */
140 static void cubetexture_unload(IWineD3DResourceImpl *resource)
141 {
142     IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *)resource;
143     UINT sub_count = texture->baseTexture.level_count * texture->baseTexture.layer_count;
144     UINT i;
145
146     TRACE("texture %p.\n", texture);
147
148     for (i = 0; i < sub_count; ++i)
149     {
150         IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)texture->baseTexture.sub_resources[i];
151
152         surface->resource.resource_ops->resource_unload((IWineD3DResourceImpl *)surface);
153         surface_set_texture_name(surface, 0, TRUE);
154         surface_set_texture_name(surface, 0, FALSE);
155     }
156
157     basetexture_unload(texture);
158 }
159
160 static const struct wined3d_texture_ops cubetexture_ops =
161 {
162     cubetexture_bind,
163     cubetexture_preload,
164 };
165
166 static const struct wined3d_resource_ops cubetexture_resource_ops =
167 {
168     cubetexture_unload,
169 };
170
171 static void cubetexture_cleanup(IWineD3DCubeTextureImpl *This)
172 {
173     UINT sub_count = This->baseTexture.level_count * This->baseTexture.layer_count;
174     UINT i;
175
176     TRACE("(%p) : Cleaning up.\n", This);
177
178     for (i = 0; i < sub_count; ++i)
179     {
180         IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)This->baseTexture.sub_resources[i];
181
182         if (surface)
183         {
184             /* Clean out the texture name we gave to the surface so that the
185              * surface doesn't try and release it. */
186             surface_set_texture_name(surface, 0, TRUE);
187             surface_set_texture_name(surface, 0, FALSE);
188             surface_set_texture_target(surface, 0);
189             surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
190             IWineD3DSurface_Release((IWineD3DSurface *)surface);
191         }
192     }
193     basetexture_cleanup((IWineD3DBaseTextureImpl *)This);
194 }
195
196 /* *******************************************
197    IWineD3DCubeTexture IUnknown parts follow
198    ******************************************* */
199
200 static HRESULT WINAPI IWineD3DCubeTextureImpl_QueryInterface(IWineD3DCubeTexture *iface, REFIID riid, LPVOID *ppobj)
201 {
202     IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface;
203     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
204     if (IsEqualGUID(riid, &IID_IUnknown)
205         || IsEqualGUID(riid, &IID_IWineD3DBase)
206         || IsEqualGUID(riid, &IID_IWineD3DResource)
207         || IsEqualGUID(riid, &IID_IWineD3DBaseTexture)
208         || IsEqualGUID(riid, &IID_IWineD3DCubeTexture)) {
209         IUnknown_AddRef(iface);
210         *ppobj = This;
211         return S_OK;
212     }
213     *ppobj = NULL;
214     return E_NOINTERFACE;
215 }
216
217 static ULONG WINAPI IWineD3DCubeTextureImpl_AddRef(IWineD3DCubeTexture *iface) {
218     IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface;
219     TRACE("(%p) : AddRef increasing from %d\n", This, This->resource.ref);
220     return InterlockedIncrement(&This->resource.ref);
221 }
222
223 /* Do not call while under the GL lock. */
224 static ULONG WINAPI IWineD3DCubeTextureImpl_Release(IWineD3DCubeTexture *iface) {
225     IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface;
226     ULONG ref;
227     TRACE("(%p) : Releasing from %d\n", This, This->resource.ref);
228     ref = InterlockedDecrement(&This->resource.ref);
229     if (!ref)
230     {
231         cubetexture_cleanup(This);
232         This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
233         HeapFree(GetProcessHeap(), 0, This);
234     }
235     return ref;
236 }
237
238 /* ****************************************************
239    IWineD3DCubeTexture IWineD3DResource parts follow
240    **************************************************** */
241 static HRESULT WINAPI IWineD3DCubeTextureImpl_SetPrivateData(IWineD3DCubeTexture *iface,
242         REFGUID riid, const void *data, DWORD data_size, DWORD flags)
243 {
244     return resource_set_private_data((IWineD3DResourceImpl *)iface, riid, data, data_size, flags);
245 }
246
247 static HRESULT WINAPI IWineD3DCubeTextureImpl_GetPrivateData(IWineD3DCubeTexture *iface,
248         REFGUID guid, void *data, DWORD *data_size)
249 {
250     return resource_get_private_data((IWineD3DResourceImpl *)iface, guid, data, data_size);
251 }
252
253 static HRESULT WINAPI IWineD3DCubeTextureImpl_FreePrivateData(IWineD3DCubeTexture *iface, REFGUID refguid)
254 {
255     return resource_free_private_data((IWineD3DResourceImpl *)iface, refguid);
256 }
257
258 static DWORD WINAPI IWineD3DCubeTextureImpl_SetPriority(IWineD3DCubeTexture *iface, DWORD priority)
259 {
260     return resource_set_priority((IWineD3DResourceImpl *)iface, priority);
261 }
262
263 static DWORD WINAPI IWineD3DCubeTextureImpl_GetPriority(IWineD3DCubeTexture *iface)
264 {
265     return resource_get_priority((IWineD3DResourceImpl *)iface);
266 }
267
268 /* Do not call while under the GL lock. */
269 static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface)
270 {
271     cubetexture_preload((IWineD3DBaseTextureImpl *)iface, SRGB_ANY);
272 }
273
274 static WINED3DRESOURCETYPE WINAPI IWineD3DCubeTextureImpl_GetType(IWineD3DCubeTexture *iface)
275 {
276     return resource_get_type((IWineD3DResourceImpl *)iface);
277 }
278
279 static void * WINAPI IWineD3DCubeTextureImpl_GetParent(IWineD3DCubeTexture *iface)
280 {
281     TRACE("iface %p.\n", iface);
282
283     return ((IWineD3DCubeTextureImpl *)iface)->resource.parent;
284 }
285
286 /* ******************************************************
287    IWineD3DCubeTexture IWineD3DBaseTexture parts follow
288    ****************************************************** */
289 static DWORD WINAPI IWineD3DCubeTextureImpl_SetLOD(IWineD3DCubeTexture *iface, DWORD LODNew) {
290     return basetexture_set_lod((IWineD3DBaseTextureImpl *)iface, LODNew);
291 }
292
293 static DWORD WINAPI IWineD3DCubeTextureImpl_GetLOD(IWineD3DCubeTexture *iface) {
294     return basetexture_get_lod((IWineD3DBaseTextureImpl *)iface);
295 }
296
297 static DWORD WINAPI IWineD3DCubeTextureImpl_GetLevelCount(IWineD3DCubeTexture *iface)
298 {
299     return basetexture_get_level_count((IWineD3DBaseTextureImpl *)iface);
300 }
301
302 static HRESULT WINAPI IWineD3DCubeTextureImpl_SetAutoGenFilterType(IWineD3DCubeTexture *iface,
303         WINED3DTEXTUREFILTERTYPE FilterType)
304 {
305   return basetexture_set_autogen_filter_type((IWineD3DBaseTextureImpl *)iface, FilterType);
306 }
307
308 static WINED3DTEXTUREFILTERTYPE WINAPI IWineD3DCubeTextureImpl_GetAutoGenFilterType(IWineD3DCubeTexture *iface)
309 {
310   return basetexture_get_autogen_filter_type((IWineD3DBaseTextureImpl *)iface);
311 }
312
313 static void WINAPI IWineD3DCubeTextureImpl_GenerateMipSubLevels(IWineD3DCubeTexture *iface)
314 {
315     basetexture_generate_mipmaps((IWineD3DBaseTextureImpl *)iface);
316 }
317
318 static BOOL WINAPI IWineD3DCubeTextureImpl_IsCondNP2(IWineD3DCubeTexture *iface)
319 {
320     TRACE("iface %p.\n", iface);
321
322     return FALSE;
323 }
324
325 static HRESULT WINAPI IWineD3DCubeTextureImpl_GetLevelDesc(IWineD3DCubeTexture *iface,
326         UINT sub_resource_idx, WINED3DSURFACE_DESC *desc)
327 {
328     IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *)iface;
329     IWineD3DSurface *surface;
330
331     TRACE("iface %p, sub_resource_idx %u, desc %p.\n", iface, sub_resource_idx, desc);
332
333     if (!(surface = (IWineD3DSurface *)basetexture_get_sub_resource(texture, sub_resource_idx)))
334     {
335         WARN("Failed to get sub-resource.\n");
336         return WINED3DERR_INVALIDCALL;
337     }
338
339     IWineD3DSurface_GetDesc(surface, desc);
340
341     return WINED3D_OK;
342 }
343
344 static HRESULT WINAPI IWineD3DCubeTextureImpl_GetCubeMapSurface(IWineD3DCubeTexture *iface,
345         UINT sub_resource_idx, IWineD3DSurface **surface)
346 {
347     IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *)iface;
348     IWineD3DSurface *s;
349
350     TRACE("iface %p, sub_resource_idx %u, surface %p.\n",
351             iface, sub_resource_idx, surface);
352
353     if (!(s = (IWineD3DSurface *)basetexture_get_sub_resource(texture, sub_resource_idx)))
354     {
355         WARN("Failed to get sub-resource.\n");
356         return WINED3DERR_INVALIDCALL;
357     }
358
359     IWineD3DSurface_AddRef(s);
360     *surface = s;
361
362     TRACE("Returning surface %p.\n", *surface);
363
364     return WINED3D_OK;
365 }
366
367 static HRESULT WINAPI IWineD3DCubeTextureImpl_Map(IWineD3DCubeTexture *iface,
368         UINT sub_resource_idx, WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
369 {
370     IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *)iface;
371     IWineD3DSurface *surface;
372
373     TRACE("iface %p, sub_resource_idx %u, locked_rect %p, rect %s, flags %#x.\n",
374             iface, sub_resource_idx, locked_rect, wine_dbgstr_rect(rect), flags);
375
376     if (!(surface = (IWineD3DSurface *)basetexture_get_sub_resource(texture, sub_resource_idx)))
377     {
378         WARN("Failed to get sub-resource.\n");
379         return WINED3DERR_INVALIDCALL;
380     }
381
382     return IWineD3DSurface_Map(surface, locked_rect, rect, flags);
383 }
384
385 static HRESULT WINAPI IWineD3DCubeTextureImpl_Unmap(IWineD3DCubeTexture *iface,
386         UINT sub_resource_idx)
387 {
388     IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *)iface;
389     IWineD3DSurface *surface;
390
391     TRACE("iface %p, sub_resource_idx %u.\n",
392             iface, sub_resource_idx);
393
394     if (!(surface = (IWineD3DSurface *)basetexture_get_sub_resource(texture, sub_resource_idx)))
395     {
396         WARN("Failed to get sub-resource.\n");
397         return WINED3DERR_INVALIDCALL;
398     }
399
400     return IWineD3DSurface_Unmap(surface);
401 }
402
403 static HRESULT WINAPI IWineD3DCubeTextureImpl_AddDirtyRect(IWineD3DCubeTexture *iface,
404         WINED3DCUBEMAP_FACES face, const RECT *dirty_rect)
405 {
406     IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl *)iface;
407     UINT sub_resource_idx = face * texture->baseTexture.level_count;
408     IWineD3DSurfaceImpl *surface;
409
410     TRACE("iface %p, face %u, dirty_rect %s.\n",
411             iface, face, wine_dbgstr_rect(dirty_rect));
412
413     if (!(surface = (IWineD3DSurfaceImpl *)basetexture_get_sub_resource(texture, sub_resource_idx)))
414     {
415         WARN("Failed to get sub-resource.\n");
416         return WINED3DERR_INVALIDCALL;
417     }
418
419     texture->baseTexture.texture_rgb.dirty = TRUE;
420     texture->baseTexture.texture_srgb.dirty = TRUE;
421     surface_add_dirty_rect(surface, dirty_rect);
422
423     return WINED3D_OK;
424 }
425
426 static const IWineD3DCubeTextureVtbl IWineD3DCubeTexture_Vtbl =
427 {
428     /* IUnknown */
429     IWineD3DCubeTextureImpl_QueryInterface,
430     IWineD3DCubeTextureImpl_AddRef,
431     IWineD3DCubeTextureImpl_Release,
432     /* IWineD3DResource */
433     IWineD3DCubeTextureImpl_GetParent,
434     IWineD3DCubeTextureImpl_SetPrivateData,
435     IWineD3DCubeTextureImpl_GetPrivateData,
436     IWineD3DCubeTextureImpl_FreePrivateData,
437     IWineD3DCubeTextureImpl_SetPriority,
438     IWineD3DCubeTextureImpl_GetPriority,
439     IWineD3DCubeTextureImpl_PreLoad,
440     IWineD3DCubeTextureImpl_GetType,
441     /* IWineD3DBaseTexture */
442     IWineD3DCubeTextureImpl_SetLOD,
443     IWineD3DCubeTextureImpl_GetLOD,
444     IWineD3DCubeTextureImpl_GetLevelCount,
445     IWineD3DCubeTextureImpl_SetAutoGenFilterType,
446     IWineD3DCubeTextureImpl_GetAutoGenFilterType,
447     IWineD3DCubeTextureImpl_GenerateMipSubLevels,
448     IWineD3DCubeTextureImpl_IsCondNP2,
449     /* IWineD3DCubeTexture */
450     IWineD3DCubeTextureImpl_GetLevelDesc,
451     IWineD3DCubeTextureImpl_GetCubeMapSurface,
452     IWineD3DCubeTextureImpl_Map,
453     IWineD3DCubeTextureImpl_Unmap,
454     IWineD3DCubeTextureImpl_AddDirtyRect
455 };
456
457 HRESULT cubetexture_init(IWineD3DCubeTextureImpl *texture, UINT edge_length, UINT levels,
458         IWineD3DDeviceImpl *device, DWORD usage, enum wined3d_format_id format_id, WINED3DPOOL pool,
459         void *parent, const struct wined3d_parent_ops *parent_ops)
460 {
461     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
462     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
463     UINT pow2_edge_length;
464     unsigned int i, j;
465     UINT tmp_w;
466     HRESULT hr;
467
468     /* TODO: It should only be possible to create textures for formats
469      * that are reported as supported. */
470     if (WINED3DFMT_UNKNOWN >= format_id)
471     {
472         WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture);
473         return WINED3DERR_INVALIDCALL;
474     }
475
476     if (!gl_info->supported[ARB_TEXTURE_CUBE_MAP] && pool != WINED3DPOOL_SCRATCH)
477     {
478         WARN("(%p) : Tried to create not supported cube texture.\n", texture);
479         return WINED3DERR_INVALIDCALL;
480     }
481
482     /* Calculate levels for mip mapping */
483     if (usage & WINED3DUSAGE_AUTOGENMIPMAP)
484     {
485         if (!gl_info->supported[SGIS_GENERATE_MIPMAP])
486         {
487             WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
488             return WINED3DERR_INVALIDCALL;
489         }
490
491         if (levels > 1)
492         {
493             WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
494             return WINED3DERR_INVALIDCALL;
495         }
496
497         levels = 1;
498     }
499     else if (!levels)
500     {
501         levels = wined3d_log2i(edge_length) + 1;
502         TRACE("Calculated levels = %u.\n", levels);
503     }
504
505     texture->lpVtbl = &IWineD3DCubeTexture_Vtbl;
506
507     hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, &cubetexture_ops,
508             6, levels, WINED3DRTYPE_CUBETEXTURE, device, usage, format, pool,
509             parent, parent_ops, &cubetexture_resource_ops);
510     if (FAILED(hr))
511     {
512         WARN("Failed to initialize basetexture, returning %#x\n", hr);
513         return hr;
514     }
515
516     /* Find the nearest pow2 match. */
517     pow2_edge_length = 1;
518     while (pow2_edge_length < edge_length) pow2_edge_length <<= 1;
519
520     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || (edge_length == pow2_edge_length))
521     {
522         /* Precalculated scaling for 'faked' non power of two texture coords. */
523         texture->baseTexture.pow2Matrix[0] = 1.0f;
524         texture->baseTexture.pow2Matrix[5] = 1.0f;
525         texture->baseTexture.pow2Matrix[10] = 1.0f;
526         texture->baseTexture.pow2Matrix[15] = 1.0f;
527     }
528     else
529     {
530         /* Precalculated scaling for 'faked' non power of two texture coords. */
531         texture->baseTexture.pow2Matrix[0] = ((float)edge_length) / ((float)pow2_edge_length);
532         texture->baseTexture.pow2Matrix[5] = ((float)edge_length) / ((float)pow2_edge_length);
533         texture->baseTexture.pow2Matrix[10] = ((float)edge_length) / ((float)pow2_edge_length);
534         texture->baseTexture.pow2Matrix[15] = 1.0f;
535         texture->baseTexture.pow2Matrix_identity = FALSE;
536     }
537     texture->baseTexture.target = GL_TEXTURE_CUBE_MAP_ARB;
538
539     /* Generate all the surfaces. */
540     tmp_w = edge_length;
541     for (i = 0; i < texture->baseTexture.level_count; ++i)
542     {
543         /* Create the 6 faces. */
544         for (j = 0; j < 6; ++j)
545         {
546             static const GLenum cube_targets[6] =
547             {
548                 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
549                 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
550                 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
551                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
552                 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
553                 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
554             };
555             UINT idx = j * texture->baseTexture.level_count + i;
556             IWineD3DSurface *surface;
557
558             hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_w,
559                     format_id, usage, pool, i /* Level */, j, &surface);
560             if (FAILED(hr))
561             {
562                 FIXME("(%p) Failed to create surface, hr %#x.\n", texture, hr);
563                 cubetexture_cleanup(texture);
564                 return hr;
565             }
566
567             surface_set_container((IWineD3DSurfaceImpl *)surface, WINED3D_CONTAINER_TEXTURE, (IWineD3DBase *)texture);
568             surface_set_texture_target((IWineD3DSurfaceImpl *)surface, cube_targets[j]);
569             texture->baseTexture.sub_resources[idx] = (IWineD3DResourceImpl *)surface;
570             TRACE("Created surface level %u @ %p.\n", i, surface);
571         }
572         tmp_w = max(1, tmp_w >> 1);
573     }
574
575     return WINED3D_OK;
576 }