xref: /reactos/dll/directx/wine/d3dx9_36/render.c (revision 6760065e)
1 #ifdef __REACTOS__
2 #include "precomp.h"
3 #else
4 /*
5  * Copyright (C) 2012 Józef Kucia
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  */
22 
23 #include "config.h"
24 #include "wine/port.h"
25 
26 #include "d3dx9_private.h"
27 #endif /* __REACTOS__ */
28 
29 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
30 
31 struct device_state
32 {
33     DWORD num_render_targets;
34     IDirect3DSurface9 **render_targets;
35     IDirect3DSurface9 *depth_stencil;
36     D3DVIEWPORT9 viewport;
37 };
38 
39 static HRESULT device_state_init(IDirect3DDevice9 *device, struct device_state *state)
40 {
41     HRESULT hr;
42     D3DCAPS9 caps;
43     unsigned int i;
44 
45     hr = IDirect3DDevice9_GetDeviceCaps(device, &caps);
46     if (FAILED(hr)) return hr;
47 
48     state->num_render_targets = caps.NumSimultaneousRTs;
49     state->render_targets = HeapAlloc(GetProcessHeap(), 0,
50         state->num_render_targets * sizeof(IDirect3DSurface9 *));
51     if (!state->render_targets)
52         return E_OUTOFMEMORY;
53 
54     for (i = 0; i < state->num_render_targets; i++)
55         state->render_targets[i] = NULL;
56     state->depth_stencil = NULL;
57     return D3D_OK;
58 }
59 
60 static void device_state_capture(IDirect3DDevice9 *device, struct device_state *state)
61 {
62     HRESULT hr;
63     unsigned int i;
64 
65     IDirect3DDevice9_GetViewport(device, &state->viewport);
66 
67     for (i = 0; i < state->num_render_targets; i++)
68     {
69         hr = IDirect3DDevice9_GetRenderTarget(device, i, &state->render_targets[i]);
70         if (FAILED(hr)) state->render_targets[i] = NULL;
71     }
72 
73     hr = IDirect3DDevice9_GetDepthStencilSurface(device, &state->depth_stencil);
74     if (FAILED(hr)) state->depth_stencil = NULL;
75 }
76 
77 static void device_state_restore(IDirect3DDevice9 *device, struct device_state *state)
78 {
79     unsigned int i;
80 
81     for (i = 0; i < state->num_render_targets; i++)
82     {
83         IDirect3DDevice9_SetRenderTarget(device, i, state->render_targets[i]);
84         if (state->render_targets[i])
85             IDirect3DSurface9_Release(state->render_targets[i]);
86         state->render_targets[i] = NULL;
87     }
88 
89     IDirect3DDevice9_SetDepthStencilSurface(device, state->depth_stencil);
90     if (state->depth_stencil)
91     {
92         IDirect3DSurface9_Release(state->depth_stencil);
93         state->depth_stencil = NULL;
94     }
95 
96     IDirect3DDevice9_SetViewport(device, &state->viewport);
97 }
98 
99 static void device_state_release(struct device_state *state)
100 {
101     unsigned int i;
102 
103     for (i = 0; i < state->num_render_targets; i++)
104     {
105         if (state->render_targets[i])
106             IDirect3DSurface9_Release(state->render_targets[i]);
107     }
108 
109     HeapFree(GetProcessHeap(), 0, state->render_targets);
110 
111     if (state->depth_stencil) IDirect3DSurface9_Release(state->depth_stencil);
112 }
113 
114 struct render_to_surface
115 {
116     ID3DXRenderToSurface ID3DXRenderToSurface_iface;
117     LONG ref;
118 
119     IDirect3DDevice9 *device;
120     D3DXRTS_DESC desc;
121 
122     IDirect3DSurface9 *dst_surface;
123 
124     IDirect3DSurface9 *render_target;
125     IDirect3DSurface9 *depth_stencil;
126 
127     struct device_state previous_state;
128 };
129 
130 static inline struct render_to_surface *impl_from_ID3DXRenderToSurface(ID3DXRenderToSurface *iface)
131 {
132     return CONTAINING_RECORD(iface, struct render_to_surface, ID3DXRenderToSurface_iface);
133 }
134 
135 static HRESULT WINAPI D3DXRenderToSurface_QueryInterface(ID3DXRenderToSurface *iface,
136                                                          REFIID riid,
137                                                          void **out)
138 {
139     TRACE("iface %p, riid %s, out %p\n", iface, debugstr_guid(riid), out);
140 
141     if (IsEqualGUID(riid, &IID_ID3DXRenderToSurface)
142             || IsEqualGUID(riid, &IID_IUnknown))
143     {
144         IUnknown_AddRef(iface);
145         *out = iface;
146         return S_OK;
147     }
148 
149     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
150 
151     *out = NULL;
152     return E_NOINTERFACE;
153 }
154 
155 static ULONG WINAPI D3DXRenderToSurface_AddRef(ID3DXRenderToSurface *iface)
156 {
157     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
158     ULONG ref = InterlockedIncrement(&render->ref);
159 
160     TRACE("%p increasing refcount to %u\n", iface, ref);
161 
162     return ref;
163 }
164 
165 static ULONG WINAPI D3DXRenderToSurface_Release(ID3DXRenderToSurface *iface)
166 {
167     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
168     ULONG ref = InterlockedDecrement(&render->ref);
169 
170     TRACE("%p decreasing refcount to %u\n", iface, ref);
171 
172     if (!ref)
173     {
174         if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface);
175 
176         if (render->render_target) IDirect3DSurface9_Release(render->render_target);
177         if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
178 
179         device_state_release(&render->previous_state);
180 
181         IDirect3DDevice9_Release(render->device);
182 
183         HeapFree(GetProcessHeap(), 0, render);
184     }
185 
186     return ref;
187 }
188 
189 static HRESULT WINAPI D3DXRenderToSurface_GetDevice(ID3DXRenderToSurface *iface,
190                                                     IDirect3DDevice9 **device)
191 {
192     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
193 
194     TRACE("(%p)->(%p)\n", iface, device);
195 
196     if (!device) return D3DERR_INVALIDCALL;
197 
198     IDirect3DDevice9_AddRef(render->device);
199     *device = render->device;
200     return D3D_OK;
201 }
202 
203 static HRESULT WINAPI D3DXRenderToSurface_GetDesc(ID3DXRenderToSurface *iface,
204                                                   D3DXRTS_DESC *desc)
205 {
206     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
207 
208     TRACE("(%p)->(%p)\n", iface, desc);
209 
210     if (!desc) return D3DERR_INVALIDCALL;
211 
212     *desc = render->desc;
213     return D3D_OK;
214 }
215 
216 static HRESULT WINAPI D3DXRenderToSurface_BeginScene(ID3DXRenderToSurface *iface,
217                                                      IDirect3DSurface9 *surface,
218                                                      const D3DVIEWPORT9 *viewport)
219 {
220     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
221     unsigned int i;
222     IDirect3DDevice9 *device;
223     D3DSURFACE_DESC surface_desc;
224     HRESULT hr = D3DERR_INVALIDCALL;
225     D3DMULTISAMPLE_TYPE multi_sample_type = D3DMULTISAMPLE_NONE;
226     DWORD multi_sample_quality = 0;
227 
228     TRACE("(%p)->(%p, %p)\n", iface, surface, viewport);
229 
230     if (!surface || render->dst_surface) return D3DERR_INVALIDCALL;
231 
232     IDirect3DSurface9_GetDesc(surface, &surface_desc);
233     if (surface_desc.Format != render->desc.Format
234             || surface_desc.Width != render->desc.Width
235             || surface_desc.Height != render->desc.Height)
236         return D3DERR_INVALIDCALL;
237 
238     if (viewport)
239     {
240         if (viewport->X > render->desc.Width || viewport->Y > render->desc.Height
241                 || viewport->X + viewport->Width > render->desc.Width
242                 || viewport->Y + viewport->Height > render->desc.Height)
243             return D3DERR_INVALIDCALL;
244 
245         if (!(surface_desc.Usage & D3DUSAGE_RENDERTARGET)
246                 && (viewport->X != 0 || viewport->Y != 0
247                 || viewport->Width != render->desc.Width
248                 || viewport->Height != render->desc.Height))
249             return D3DERR_INVALIDCALL;
250     }
251 
252     device = render->device;
253 
254     device_state_capture(device, &render->previous_state);
255 
256     /* prepare for rendering to surface */
257     for (i = 1; i < render->previous_state.num_render_targets; i++)
258         IDirect3DDevice9_SetRenderTarget(device, i, NULL);
259 
260     if (surface_desc.Usage & D3DUSAGE_RENDERTARGET)
261     {
262         hr = IDirect3DDevice9_SetRenderTarget(device, 0, surface);
263         multi_sample_type = surface_desc.MultiSampleType;
264         multi_sample_quality = surface_desc.MultiSampleQuality;
265     }
266     else
267     {
268         hr = IDirect3DDevice9_CreateRenderTarget(device, render->desc.Width, render->desc.Height,
269                 render->desc.Format, multi_sample_type, multi_sample_quality, FALSE,
270                 &render->render_target, NULL);
271         if (FAILED(hr)) goto cleanup;
272         hr = IDirect3DDevice9_SetRenderTarget(device, 0, render->render_target);
273     }
274 
275     if (FAILED(hr)) goto cleanup;
276 
277     if (render->desc.DepthStencil)
278     {
279         hr = IDirect3DDevice9_CreateDepthStencilSurface(device, render->desc.Width, render->desc.Height,
280                 render->desc.DepthStencilFormat, multi_sample_type, multi_sample_quality, TRUE,
281                 &render->depth_stencil, NULL);
282     }
283     else render->depth_stencil = NULL;
284 
285     if (FAILED(hr)) goto cleanup;
286 
287     hr = IDirect3DDevice9_SetDepthStencilSurface(device, render->depth_stencil);
288     if (FAILED(hr)) goto cleanup;
289 
290     if (viewport) IDirect3DDevice9_SetViewport(device, viewport);
291 
292     IDirect3DSurface9_AddRef(surface);
293     render->dst_surface = surface;
294     return IDirect3DDevice9_BeginScene(device);
295 
296 cleanup:
297     device_state_restore(device, &render->previous_state);
298 
299     if (render->dst_surface) IDirect3DSurface9_Release(render->dst_surface);
300     render->dst_surface = NULL;
301 
302     if (render->render_target) IDirect3DSurface9_Release(render->render_target);
303     render->render_target = NULL;
304     if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
305     render->depth_stencil = NULL;
306 
307     return hr;
308 }
309 
310 static HRESULT WINAPI D3DXRenderToSurface_EndScene(ID3DXRenderToSurface *iface,
311                                                    DWORD filter)
312 {
313     struct render_to_surface *render = impl_from_ID3DXRenderToSurface(iface);
314     HRESULT hr;
315 
316     TRACE("(%p)->(%#x)\n", iface, filter);
317 
318     if (!render->dst_surface) return D3DERR_INVALIDCALL;
319 
320     hr = IDirect3DDevice9_EndScene(render->device);
321 
322     /* copy render target data to destination surface, if needed */
323     if (render->render_target)
324     {
325         hr = D3DXLoadSurfaceFromSurface(render->dst_surface, NULL, NULL,
326                 render->render_target, NULL, NULL, filter, 0);
327         if (FAILED(hr)) ERR("Copying render target data to surface failed %#x\n", hr);
328     }
329 
330     device_state_restore(render->device, &render->previous_state);
331 
332     /* release resources */
333     if (render->render_target)
334     {
335         IDirect3DSurface9_Release(render->render_target);
336         render->render_target = NULL;
337     }
338 
339     if (render->depth_stencil)
340     {
341         IDirect3DSurface9_Release(render->depth_stencil);
342         render->depth_stencil = NULL;
343     }
344 
345     IDirect3DSurface9_Release(render->dst_surface);
346     render->dst_surface = NULL;
347 
348     return hr;
349 }
350 
351 static HRESULT WINAPI D3DXRenderToSurface_OnLostDevice(ID3DXRenderToSurface *iface)
352 {
353     FIXME("(%p)->(): stub\n", iface);
354     return D3D_OK;
355 }
356 
357 static HRESULT WINAPI D3DXRenderToSurface_OnResetDevice(ID3DXRenderToSurface *iface)
358 {
359     FIXME("(%p)->(): stub\n", iface);
360     return D3D_OK;
361 }
362 
363 static const ID3DXRenderToSurfaceVtbl render_to_surface_vtbl =
364 {
365     /* IUnknown methods */
366     D3DXRenderToSurface_QueryInterface,
367     D3DXRenderToSurface_AddRef,
368     D3DXRenderToSurface_Release,
369     /* ID3DXRenderToSurface methods */
370     D3DXRenderToSurface_GetDevice,
371     D3DXRenderToSurface_GetDesc,
372     D3DXRenderToSurface_BeginScene,
373     D3DXRenderToSurface_EndScene,
374     D3DXRenderToSurface_OnLostDevice,
375     D3DXRenderToSurface_OnResetDevice
376 };
377 
378 HRESULT WINAPI D3DXCreateRenderToSurface(IDirect3DDevice9 *device,
379                                          UINT width,
380                                          UINT height,
381                                          D3DFORMAT format,
382                                          BOOL depth_stencil,
383                                          D3DFORMAT depth_stencil_format,
384                                          ID3DXRenderToSurface **out)
385 {
386     HRESULT hr;
387     struct render_to_surface *render;
388 
389     TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, width, height, format,
390             depth_stencil, depth_stencil_format, out);
391 
392     if (!device || !out) return D3DERR_INVALIDCALL;
393 
394     render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_surface));
395     if (!render) return E_OUTOFMEMORY;
396 
397     render->ID3DXRenderToSurface_iface.lpVtbl = &render_to_surface_vtbl;
398     render->ref = 1;
399 
400     render->desc.Width = width;
401     render->desc.Height = height;
402     render->desc.Format = format;
403     render->desc.DepthStencil = depth_stencil;
404     render->desc.DepthStencilFormat = depth_stencil_format;
405 
406     render->dst_surface = NULL;
407     render->render_target = NULL;
408     render->depth_stencil = NULL;
409 
410     hr = device_state_init(device, &render->previous_state);
411     if (FAILED(hr))
412     {
413         HeapFree(GetProcessHeap(), 0, render);
414         return hr;
415     }
416 
417     IDirect3DDevice9_AddRef(device);
418     render->device = device;
419 
420     *out = &render->ID3DXRenderToSurface_iface;
421     return D3D_OK;
422 }
423 
424 
425 enum render_state
426 {
427     INITIAL,
428 
429     CUBE_BEGIN,
430     CUBE_FACE
431 };
432 
433 struct render_to_envmap
434 {
435     ID3DXRenderToEnvMap ID3DXRenderToEnvMap_iface;
436     LONG ref;
437 
438     IDirect3DDevice9 *device;
439     D3DXRTE_DESC desc;
440 
441     enum render_state state;
442     struct device_state previous_device_state;
443 
444     D3DCUBEMAP_FACES face;
445     DWORD filter;
446 
447     IDirect3DSurface9 *render_target;
448     IDirect3DSurface9 *depth_stencil;
449 
450     IDirect3DCubeTexture9 *dst_cube_texture;
451 };
452 
453 static void copy_render_target_to_cube_texture_face(IDirect3DCubeTexture9 *cube_texture,
454         D3DCUBEMAP_FACES face, IDirect3DSurface9 *render_target, DWORD filter)
455 {
456     HRESULT hr;
457     IDirect3DSurface9 *cube_surface;
458 
459     IDirect3DCubeTexture9_GetCubeMapSurface(cube_texture, face, 0, &cube_surface);
460 
461     hr = D3DXLoadSurfaceFromSurface(cube_surface, NULL, NULL, render_target, NULL, NULL, filter, 0);
462     if (FAILED(hr)) ERR("Copying render target data to surface failed %#x\n", hr);
463 
464     IDirect3DSurface9_Release(cube_surface);
465 }
466 
467 static inline struct render_to_envmap *impl_from_ID3DXRenderToEnvMap(ID3DXRenderToEnvMap *iface)
468 {
469     return CONTAINING_RECORD(iface, struct render_to_envmap, ID3DXRenderToEnvMap_iface);
470 }
471 
472 static HRESULT WINAPI D3DXRenderToEnvMap_QueryInterface(ID3DXRenderToEnvMap *iface,
473                                                         REFIID riid,
474                                                         void **out)
475 {
476     TRACE("iface %p, riid %s, out %p\n", iface, debugstr_guid(riid), out);
477 
478     if (IsEqualGUID(riid, &IID_ID3DXRenderToEnvMap)
479             || IsEqualGUID(riid, &IID_IUnknown))
480     {
481         IUnknown_AddRef(iface);
482         *out = iface;
483         return S_OK;
484     }
485 
486     WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid));
487 
488     *out = NULL;
489     return E_NOINTERFACE;
490 }
491 
492 static ULONG WINAPI D3DXRenderToEnvMap_AddRef(ID3DXRenderToEnvMap *iface)
493 {
494     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
495     ULONG ref = InterlockedIncrement(&render->ref);
496 
497     TRACE("%p increasing refcount to %u\n", iface, ref);
498 
499     return ref;
500 }
501 
502 static ULONG WINAPI D3DXRenderToEnvMap_Release(ID3DXRenderToEnvMap *iface)
503 {
504     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
505     ULONG ref = InterlockedDecrement(&render->ref);
506 
507     TRACE("%p decreasing refcount to %u\n", iface, ref);
508 
509     if (!ref)
510     {
511         if (render->dst_cube_texture) IDirect3DSurface9_Release(render->dst_cube_texture);
512 
513         if (render->render_target) IDirect3DSurface9_Release(render->render_target);
514         if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
515 
516         device_state_release(&render->previous_device_state);
517 
518         IDirect3DDevice9_Release(render->device);
519 
520         HeapFree(GetProcessHeap(), 0, render);
521     }
522 
523     return ref;
524 }
525 
526 static HRESULT WINAPI D3DXRenderToEnvMap_GetDevice(ID3DXRenderToEnvMap *iface,
527                                                    IDirect3DDevice9 **device)
528 {
529     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
530 
531     TRACE("(%p)->(%p)\n", iface, device);
532 
533     if (!device) return D3DERR_INVALIDCALL;
534 
535     IDirect3DDevice9_AddRef(render->device);
536     *device = render->device;
537     return D3D_OK;
538 }
539 
540 static HRESULT WINAPI D3DXRenderToEnvMap_GetDesc(ID3DXRenderToEnvMap *iface,
541                                                  D3DXRTE_DESC *desc)
542 {
543     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
544 
545     TRACE("(%p)->(%p)\n", iface, desc);
546 
547     if (!desc) return D3DERR_INVALIDCALL;
548 
549     *desc = render->desc;
550     return D3D_OK;
551 }
552 
553 static HRESULT WINAPI D3DXRenderToEnvMap_BeginCube(ID3DXRenderToEnvMap *iface,
554                                                    IDirect3DCubeTexture9 *texture)
555 {
556     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
557     HRESULT hr;
558     D3DSURFACE_DESC level_desc;
559 
560     TRACE("(%p)->(%p)\n", iface, texture);
561 
562     if (!texture) return D3DERR_INVALIDCALL;
563 
564     if (render->state != INITIAL) return D3DERR_INVALIDCALL;
565 
566     IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &level_desc);
567     if (level_desc.Format != render->desc.Format || level_desc.Width != render->desc.Size)
568         return D3DERR_INVALIDCALL;
569 
570     if (!(level_desc.Usage & D3DUSAGE_RENDERTARGET))
571     {
572         hr = IDirect3DDevice9_CreateRenderTarget(render->device, level_desc.Width, level_desc.Height,
573                 level_desc.Format, level_desc.MultiSampleType, level_desc.MultiSampleQuality,
574                 TRUE, &render->render_target, NULL);
575         if (FAILED(hr)) goto cleanup;
576         IDirect3DCubeTexture9_GetLevelDesc(texture, 0, &level_desc);
577     }
578 
579     if (render->desc.DepthStencil)
580     {
581         hr = IDirect3DDevice9_CreateDepthStencilSurface(render->device, level_desc.Width, level_desc.Height,
582                 render->desc.DepthStencilFormat, level_desc.MultiSampleType, level_desc.MultiSampleQuality,
583                 TRUE, &render->depth_stencil, NULL);
584         if (FAILED(hr)) goto cleanup;
585     }
586 
587     IDirect3DCubeTexture9_AddRef(texture);
588     render->dst_cube_texture = texture;
589     render->state = CUBE_BEGIN;
590     return D3D_OK;
591 
592 cleanup:
593     if (render->dst_cube_texture) IDirect3DSurface9_Release(render->dst_cube_texture);
594     render->dst_cube_texture = NULL;
595 
596     if (render->render_target) IDirect3DSurface9_Release(render->render_target);
597     render->render_target = NULL;
598     if (render->depth_stencil) IDirect3DSurface9_Release(render->depth_stencil);
599     render->depth_stencil = NULL;
600 
601     return hr;
602 }
603 
604 static HRESULT WINAPI D3DXRenderToEnvMap_BeginSphere(ID3DXRenderToEnvMap *iface,
605                                                      IDirect3DTexture9 *texture)
606 {
607     FIXME("(%p)->(%p): stub\n", iface, texture);
608     return E_NOTIMPL;
609 }
610 
611 static HRESULT WINAPI D3DXRenderToEnvMap_BeginHemisphere(ID3DXRenderToEnvMap *iface,
612                                                          IDirect3DTexture9 *pos_z_texture,
613                                                          IDirect3DTexture9 *neg_z_texture)
614 {
615     FIXME("(%p)->(%p, %p): stub\n", iface, pos_z_texture, neg_z_texture);
616     return E_NOTIMPL;
617 }
618 
619 static HRESULT WINAPI D3DXRenderToEnvMap_BeginParabolic(ID3DXRenderToEnvMap *iface,
620                                                         IDirect3DTexture9 *pos_z_texture,
621                                                         IDirect3DTexture9 *neg_z_texture)
622 {
623     FIXME("(%p)->(%p, %p): stub\n", iface, pos_z_texture, neg_z_texture);
624     return E_NOTIMPL;
625 }
626 
627 static HRESULT WINAPI D3DXRenderToEnvMap_Face(ID3DXRenderToEnvMap *iface,
628                                               D3DCUBEMAP_FACES face,
629                                               DWORD filter)
630 {
631     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
632     HRESULT hr;
633     unsigned int i;
634 
635     TRACE("(%p)->(%u, %#x)\n", iface, face, filter);
636 
637     if (render->state == CUBE_FACE)
638     {
639         IDirect3DDevice9_EndScene(render->device);
640         if (render->render_target)
641             copy_render_target_to_cube_texture_face(render->dst_cube_texture, render->face,
642                     render->render_target, render->filter);
643 
644         device_state_restore(render->device, &render->previous_device_state);
645 
646         render->state = CUBE_BEGIN;
647     }
648     else if (render->state != CUBE_BEGIN)
649         return D3DERR_INVALIDCALL;
650 
651     device_state_capture(render->device, &render->previous_device_state);
652 
653     for (i = 1; i < render->previous_device_state.num_render_targets; i++)
654         IDirect3DDevice9_SetRenderTarget(render->device, i, NULL);
655 
656     if (!render->render_target)
657     {
658         IDirect3DSurface9 *render_target;
659         IDirect3DCubeTexture9_GetCubeMapSurface(render->dst_cube_texture, face, 0, &render_target);
660         hr = IDirect3DDevice9_SetRenderTarget(render->device, 0, render_target);
661         IDirect3DSurface9_Release(render_target);
662     }
663     else hr = IDirect3DDevice9_SetRenderTarget(render->device, 0, render->render_target);
664 
665     if (FAILED(hr)) goto cleanup;
666 
667     hr = IDirect3DDevice9_SetDepthStencilSurface(render->device, render->depth_stencil);
668     if (FAILED(hr)) goto cleanup;
669 
670     render->state = CUBE_FACE;
671     render->face = face;
672     render->filter = filter;
673     return IDirect3DDevice9_BeginScene(render->device);
674 
675 cleanup:
676     device_state_restore(render->device, &render->previous_device_state);
677     return hr;
678 }
679 
680 static HRESULT WINAPI D3DXRenderToEnvMap_End(ID3DXRenderToEnvMap *iface,
681                                              DWORD filter)
682 {
683     struct render_to_envmap *render = impl_from_ID3DXRenderToEnvMap(iface);
684 
685     TRACE("(%p)->(%#x)\n", iface, filter);
686 
687     if (render->state == INITIAL) return D3DERR_INVALIDCALL;
688 
689     if (render->state == CUBE_FACE)
690     {
691         IDirect3DDevice9_EndScene(render->device);
692         if (render->render_target)
693             copy_render_target_to_cube_texture_face(render->dst_cube_texture, render->face,
694                     render->render_target, render->filter);
695 
696         device_state_restore(render->device, &render->previous_device_state);
697     }
698 
699     D3DXFilterTexture((IDirect3DBaseTexture9 *)render->dst_cube_texture, NULL, 0, filter);
700 
701     if (render->render_target)
702     {
703         IDirect3DSurface9_Release(render->render_target);
704         render->render_target = NULL;
705     }
706 
707     if (render->depth_stencil)
708     {
709         IDirect3DSurface9_Release(render->depth_stencil);
710         render->depth_stencil = NULL;
711     }
712 
713     IDirect3DSurface9_Release(render->dst_cube_texture);
714     render->dst_cube_texture = NULL;
715 
716     render->state = INITIAL;
717     return D3D_OK;
718 }
719 
720 static HRESULT WINAPI D3DXRenderToEnvMap_OnLostDevice(ID3DXRenderToEnvMap *iface)
721 {
722     FIXME("(%p)->(): stub\n", iface);
723     return D3D_OK;
724 }
725 
726 static HRESULT WINAPI D3DXRenderToEnvMap_OnResetDevice(ID3DXRenderToEnvMap *iface)
727 {
728     FIXME("(%p)->(): stub\n", iface);
729     return D3D_OK;
730 }
731 
732 static const ID3DXRenderToEnvMapVtbl render_to_envmap_vtbl =
733 {
734     /* IUnknown methods */
735     D3DXRenderToEnvMap_QueryInterface,
736     D3DXRenderToEnvMap_AddRef,
737     D3DXRenderToEnvMap_Release,
738     /* ID3DXRenderToEnvMap methods */
739     D3DXRenderToEnvMap_GetDevice,
740     D3DXRenderToEnvMap_GetDesc,
741     D3DXRenderToEnvMap_BeginCube,
742     D3DXRenderToEnvMap_BeginSphere,
743     D3DXRenderToEnvMap_BeginHemisphere,
744     D3DXRenderToEnvMap_BeginParabolic,
745     D3DXRenderToEnvMap_Face,
746     D3DXRenderToEnvMap_End,
747     D3DXRenderToEnvMap_OnLostDevice,
748     D3DXRenderToEnvMap_OnResetDevice
749 };
750 
751 HRESULT WINAPI D3DXCreateRenderToEnvMap(IDirect3DDevice9 *device,
752                                         UINT size,
753                                         UINT mip_levels,
754                                         D3DFORMAT format,
755                                         BOOL depth_stencil,
756                                         D3DFORMAT depth_stencil_format,
757                                         ID3DXRenderToEnvMap **out)
758 {
759     HRESULT hr;
760     struct render_to_envmap *render;
761 
762     TRACE("(%p, %u, %u, %#x, %d, %#x, %p)\n", device, size, mip_levels,
763             format, depth_stencil, depth_stencil_format, out);
764 
765     if (!device || !out) return D3DERR_INVALIDCALL;
766 
767     hr = D3DXCheckTextureRequirements(device, &size, &size, &mip_levels,
768             D3DUSAGE_RENDERTARGET, &format, D3DPOOL_DEFAULT);
769     if (FAILED(hr)) return hr;
770 
771     render = HeapAlloc(GetProcessHeap(), 0, sizeof(struct render_to_envmap));
772     if (!render) return E_OUTOFMEMORY;
773 
774     render->ID3DXRenderToEnvMap_iface.lpVtbl = &render_to_envmap_vtbl;
775     render->ref = 1;
776 
777     render->desc.Size = size;
778     render->desc.MipLevels = mip_levels;
779     render->desc.Format = format;
780     render->desc.DepthStencil = depth_stencil;
781     render->desc.DepthStencilFormat = depth_stencil_format;
782 
783     render->state = INITIAL;
784     render->render_target = NULL;
785     render->depth_stencil = NULL;
786     render->dst_cube_texture = NULL;
787 
788     hr = device_state_init(device, &render->previous_device_state);
789     if (FAILED(hr))
790     {
791         HeapFree(GetProcessHeap(), 0, render);
792         return hr;
793     }
794 
795     IDirect3DDevice9_AddRef(device);
796     render->device = device;
797 
798     *out = &render->ID3DXRenderToEnvMap_iface;
799     return D3D_OK;
800 }
801