texture.c revision 75c2e4cdb9fd3ba419cdb376d775c17b068dde9f
/*
* Copyright 2002-2005 Jason Edmeades
* Copyright 2002-2005 Raphael Junqueira
* Copyright 2005 Oliver Stieber
* Copyright 2007-2009, 2013 Stefan Dösinger for CodeWeavers
* Copyright 2009-2011 Henri Verbeet for CodeWeavers
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wined3d_private.h"
#ifdef VBOX_WITH_WDDM
# include "../../common/VBoxVideoTools.h"
#endif
static HRESULT wined3d_texture_init(struct wined3d_texture *texture, const struct wined3d_texture_ops *texture_ops,
UINT layer_count, UINT level_count, const struct wined3d_resource_desc *desc, struct wined3d_device *device,
void *parent, const struct wined3d_parent_ops *parent_ops, const struct wined3d_resource_ops *resource_ops
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
TRACE("texture %p, texture_ops %p, layer_count %u, level_count %u, resource_type %s, format %s, "
"multisample_type %#x, multisample_quality %#x, usage %s, pool %s, width %u, height %u, depth %u, "
"device %p, parent %p, parent_ops %p, resource_ops %p.\n",
#ifdef VBOX_WITH_WDDM
#else
#endif
{
return hr;
}
if (!texture->sub_resources)
{
ERR("Failed to allocate sub-resource array.\n");
return E_OUTOFMEMORY;
}
texture->filter_type = (desc->usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3D_TEXF_LINEAR : WINED3D_TEXF_NONE;
{
}
else
{
}
return WINED3D_OK;
}
/* A GL context is provided by the caller */
{
#ifdef VBOX_WITH_WDDM
#else
#endif
}
{
{
}
}
{
UINT i;
#ifdef VBOX_WITH_WINE_FIX_TEXCLEAR
/* make texture unload first, because otherwise we may fail on context_acquire done for texture cleanup
* because the swapchain's surfaces might be destroyed and we may fail to select any render target in context_acquire */
#endif
for (i = 0; i < sub_count; ++i)
{
if (sub_resource)
}
#ifndef VBOX_WITH_WINE_FIX_TEXCLEAR
#endif
}
{
}
/* Context activation is done by the caller. */
{
struct gl_texture *gl_tex;
TRACE("texture %p, context %p, srgb %#x, set_surface_desc %p.\n", texture, context, srgb, set_surface_desc);
/* sRGB mode cache for preload() calls outside drawprim. */
if (srgb)
else
/* Generate a texture name if we don't already have one. */
{
#ifdef VBOX_WITH_WDDM
{
ERR("should not be here!");
}
else
#endif
{
#ifdef VBOX_WITH_WDDM
new_texture = TRUE;
#endif
*set_surface_desc = TRUE;
checkGLcall("glGenTextures");
#ifdef VBOX_WITH_WDDM
if (VBOXSHRC_IS_SHARED(texture))
{
}
#endif
}
#ifndef VBOX
{
/* Tell OpenGL to try and keep this texture in video ram (well mostly). */
}
#else
/* chromium code on host fails to resolve texture name to texture obj,
* most likely because the texture does not get created until it is bound
* @todo: investigate */
#endif
/* Initialise the state of the texture object to the OpenGL defaults,
* not the D3D defaults. */
else
#ifndef VBOX_WITH_WDDM
new_texture = TRUE;
#endif
#ifdef VBOX_WITH_WDDM
if (new_texture
#else
#endif
{
/* This means double binding the texture at creation, but keeps
* the code simpler all in all, and the run-time path free from
* additional checks. */
checkGLcall("glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)");
}
}
else
{
}
{
if (new_texture)
{
/* For a new texture we have to set the texture levels after
* binding the texture. Beware that texture rectangles do not
* support mipmapping, but set the maxmiplevel if we're relying
* on the partial GL_ARB_texture_non_power_of_two emulation with
* texture rectangles. (I.e., do not care about cond_np2 here,
* just look for GL_TEXTURE_RECTANGLE_ARB.) */
if (target != GL_TEXTURE_RECTANGLE_ARB)
{
checkGLcall("glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, texture->level_count)");
}
if (target == GL_TEXTURE_CUBE_MAP_ARB)
{
/* Cubemaps are always set to clamp, regardless of the sampler state. */
}
}
}
else
{
ERR("This texture doesn't have an OpenGL texture assigned to it.\n");
}
return hr;
}
/* Context activation is done by the caller. */
{
{
return;
}
/* Cubemaps are always set to clamp, regardless of the sampler state. */
if (target == GL_TEXTURE_CUBE_MAP_ARB
else
checkGLcall("glTexParameteri(target, param, gl_wrap)");
}
/* Context activation is done by the caller (state handler). */
const struct wined3d_gl_info *gl_info)
{
struct gl_texture *gl_tex;
/* This function relies on the correct texture being bound and loaded. */
{
}
{
}
{
}
{
float col[4];
checkGLcall("glTexParameterfv(..., GL_TEXTURE_BORDER_COLOR, ...)");
}
{
if (state > WINED3D_TEXF_ANISOTROPIC)
}
{
{
FIXME("Unrecognized or unsupported MIN_FILTER value %#x MIP_FILTER value %#x.\n",
}
TRACE("ValueMIN=%#x, ValueMIP=%#x, setting MINFILTER to %#x.\n",
checkGLcall("glTexParameter GL_TEXTURE_MIN_FILTER, ...");
if (!cond_np2)
{
/* texture->lod is already clamped in the setter. */
else
/* Note that WINED3D_SAMP_MAX_MIP_LEVEL specifies the largest mipmap
* (default 0), while GL_TEXTURE_MAX_LEVEL specifies the smallest
* mimap used (default 1000). So WINED3D_SAMP_MAX_MIP_LEVEL
* corresponds to GL_TEXTURE_BASE_LEVEL. */
}
}
|| cond_np2)
aniso = 1;
else
{
{
checkGLcall("glTexParameteri(GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso)");
}
else
{
WARN("Anisotropic filtering not supported.\n");
}
}
/* These should always be the same unless EXT_texture_sRGB_decode is supported. */
{
checkGLcall("glTexParameteri(GL_TEXTURE_SRGB_DECODE_EXT)");
}
{
{
gl_info->gl_ops.gl.p_glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
checkGLcall("glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB)");
}
else
{
checkGLcall("glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE)");
}
}
}
{
return refcount;
}
/* Do not call while under the GL lock. */
{
if (!refcount)
{
}
return refcount;
}
{
}
{
}
{
}
/* Do not call while under the GL lock. */
{
}
{
}
{
/* The d3d9:texture test shows that SetLOD is ignored on non-managed
* textures. The call always returns 0, and GetLOD always returns 0. */
{
return 0;
}
{
}
return old;
}
{
}
{
return texture->level_count;
}
{
{
WARN("Texture doesn't have AUTOGENMIPMAP usage.\n");
return WINED3DERR_INVALIDCALL;
}
return WINED3D_OK;
}
enum wined3d_texture_filter_type CDECL wined3d_texture_get_autogen_filter_type(const struct wined3d_texture *texture)
{
return texture->filter_type;
}
{
/* TODO: Implement filters using GL_SGI_generate_mipmaps. */
}
{
if (sub_resource_idx >= sub_count)
{
return NULL;
}
}
{
struct wined3d_resource *sub_resource;
{
WARN("Failed to get sub-resource.\n");
return WINED3DERR_INVALIDCALL;
}
return WINED3D_OK;
}
/* Context activation is done by the caller. */
{
{
struct gl_texture *gl_tex;
UINT i;
for (i = 0; i < sub_count; ++i)
{
}
/* Conditinal non power of two textures use a different clamping
* default. If we're using the GL_WINE_normalized_texrect partial
* driver emulation, we're dealing with a GL_TEXTURE_2D texture which
* has the address mode set to repeat - something that prevents us
* from hitting the accelerated codepath. Thus manually set the GL
* state. The same applies to filtering. Even if the texture has only
* one mip level, the default LINEAR_MIPMAP_LINEAR filter causes a SW
* fallback on macos. */
{
#ifdef VBOX_WITH_WDDM
if (!VBOXSHRC_IS_SHARED_OPENED(texture))
#endif
{
checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
checkGLcall("glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
checkGLcall("glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
checkGLcall("glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
}
}
}
return hr;
}
{
switch (srgb)
{
case SRGB_RGB:
return FALSE;
case SRGB_SRGB:
return TRUE;
default:
}
}
/* Do not call while under the GL lock. */
{
struct gl_texture *gl_tex;
UINT i;
{
/* No danger of recursive calls, context_acquire() sets isInDraw to TRUE
* when loading offscreen render targets into the texture. */
}
{
/* Reload the surfaces if the texture is marked dirty. */
for (i = 0; i < sub_count; ++i)
{
}
}
else
{
}
/* No longer dirty. */
}
const struct wined3d_box *dirty_region)
{
}
{
/* Clean out the texture name we gave to the surface so that the
* surface doesn't try and release it. */
surface_set_texture_target(surface, 0, 0);
}
/* Do not call while under the GL lock. */
{
UINT i;
for (i = 0; i < sub_count; ++i)
{
}
}
static const struct wined3d_texture_ops texture2d_ops =
{
};
static const struct wined3d_resource_ops texture2d_resource_ops =
{
};
static HRESULT cubetexture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
const struct wined3d_parent_ops *parent_ops
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
struct wined3d_resource_desc surface_desc;
unsigned int i, j;
/* TODO: It should only be possible to create textures for formats
* that are reported as supported. */
{
return WINED3DERR_INVALIDCALL;
}
{
return WINED3DERR_INVALIDCALL;
}
/* Calculate levels for mip mapping */
{
{
WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
if (levels > 1)
{
WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
levels = 1;
}
else if (!levels)
{
}
{
pow2_edge_length <<= 1;
{
{
/* SCRATCH textures cannot be used for texturing */
WARN("Creating a scratch NPOT cube texture despite lack of HW support.\n");
}
else
{
WARN("Attempted to create a NPOT cube texture (edge length %u) without GL support.\n", desc->width);
return WINED3DERR_INVALIDCALL;
}
}
}
#ifdef VBOX_WITH_WDDM
#else
#endif
{
return hr;
}
/* Generate all the surfaces. */
surface_desc = *desc;
for (i = 0; i < texture->level_count; ++i)
{
/* Create the 6 faces. */
for (j = 0; j < 6; ++j)
{
{
};
struct wined3d_surface *surface;
#ifdef VBOX_WITH_WDDM
)))
#else
#endif
{
return hr;
}
}
}
#ifdef VBOX_WITH_WDDM
if (VBOXSHRC_IS_SHARED(texture))
{
for (i = 0; i < texture->level_count; ++i)
{
for (j = 0; j < 6; ++j)
{
}
}
#ifdef DEBUG
for (i = 0; i < texture->level_count; ++i)
{
for (j = 0; j < 6; ++j)
{
}
}
#endif
if (!VBOXSHRC_IS_SHARED_OPENED(texture))
{
for (i = 0; i < texture->level_count; ++i)
{
for (j = 0; j < 6; ++j)
{
}
}
Assert(!(*shared_handle));
}
else
{
else
for (i = 0; i < texture->level_count; ++i)
{
for (j = 0; j < 6; ++j)
{
}
}
}
#ifdef DEBUG
for (i = 0; i < texture->level_count; ++i)
{
for (j = 0; j < 6; ++j)
{
Assert((GLuint)(*shared_handle) == surface_from_resource(texture->sub_resources[idx])->texture_name);
}
}
#endif
#ifdef DEBUG
for (i = 0; i < texture->level_count; ++i)
{
for (j = 0; j < 6; ++j)
{
Assert((GLuint)(*shared_handle) == surface_from_resource(texture->sub_resources[idx])->texture_name);
}
}
#endif
/* flush to ensure the texture is allocated/referenced before it is used/released by another
}
else
{
}
#endif
return WINED3D_OK;
}
static HRESULT texture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
const struct wined3d_parent_ops *parent_ops
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
struct wined3d_resource_desc surface_desc;
unsigned int i;
/* TODO: It should only be possible to create textures for formats
* that are reported as supported. */
{
return WINED3DERR_INVALIDCALL;
}
/* Non-power2 support. */
{
}
else
{
/* Find the nearest pow2 match. */
pow2_width <<= 1;
pow2_height <<= 1;
{
/* levels == 0 returns an error as well */
if (levels != 1)
{
{
WARN("Creating a scratch mipmapped NPOT texture despite lack of HW support.\n");
}
else
{
WARN("Attempted to create a mipmapped NPOT texture without unconditional NPOT support.\n");
return WINED3DERR_INVALIDCALL;
}
}
}
}
/* Calculate levels for mip mapping. */
{
{
WARN("No mipmap generation support, returning WINED3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
if (levels > 1)
{
WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning WINED3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
levels = 1;
}
else if (!levels)
{
}
#ifdef VBOX_WITH_WDDM
#else
#endif
{
return hr;
}
/* Precalculated scaling for 'faked' non power of two texture coords.
* Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
* is used in combination with texture uploads (RTL_READTEX). The reason is that EXT_PALETTED_TEXTURE
* doesn't work in combination with ARB_TEXTURE_RECTANGLE. */
{
}
else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (desc->width != pow2_width || desc->height != pow2_height)
{
else
}
else
{
{
}
else
{
}
}
/* Generate all the surfaces. */
surface_desc = *desc;
for (i = 0; i < texture->level_count; ++i)
{
struct wined3d_surface *surface;
/* Use the callback to create the texture surface. */
#ifdef VBOX_WITH_WDDM
, NULL /* <- we first create a surface in an average "non-shared" fashion and initialize its share properties later (see below)
* this is done this way because the surface does not have its parent (texture) setup properly
* thus we can not initialize texture at this stage */
)))
#else
#endif
{
return hr;
}
/* Calculate the next mipmap level. */
}
#ifdef VBOX_WITH_WDDM
if (VBOXSHRC_IS_SHARED(texture))
{
for (i = 0; i < texture->level_count; ++i)
{
}
#ifdef DEBUG
for (i = 0; i < texture->level_count; ++i)
{
}
#endif
if (!VBOXSHRC_IS_SHARED_OPENED(texture))
{
for (i = 0; i < texture->level_count; ++i)
{
}
Assert(!(*shared_handle));
}
else
{
else
{
}
for (i = 0; i < texture->level_count; ++i)
{
}
}
#ifdef DEBUG
for (i = 0; i < texture->level_count; ++i)
{
}
#endif
/* flush to ensure the texture is allocated/referenced before it is used/released by another
}
else
{
}
#endif
return WINED3D_OK;
}
/* Context activation is done by the caller. */
{
}
/* Do not call while under the GL lock. */
{
struct wined3d_context *context;
unsigned int i;
/* TODO: Use already acquired context when possible. */
{
if (srgb_was_toggled)
{
if (sampler_srgb)
else
}
}
/* If the texture is marked dirty or the sRGB sampler setting has changed
* since the last load then reload the volumes. */
{
for (i = 0; i < texture->level_count; ++i)
{
}
}
else if (srgb_was_toggled)
{
for (i = 0; i < texture->level_count; ++i)
{
}
}
else
{
}
/* No longer dirty */
}
const struct wined3d_box *dirty_region)
{
}
{
/* Cleanup the container. */
}
/* Do not call while under the GL lock. */
{
UINT i;
for (i = 0; i < texture->level_count; ++i)
{
}
}
static const struct wined3d_texture_ops texture3d_ops =
{
};
static const struct wined3d_resource_ops texture3d_resource_ops =
{
};
static HRESULT volumetexture_init(struct wined3d_texture *texture, const struct wined3d_resource_desc *desc,
UINT levels, struct wined3d_device *device, void *parent, const struct wined3d_parent_ops *parent_ops
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
unsigned int i;
#ifdef VBOX_WITH_WDDM
if (shared_handle)
{
ERR("shared handle support for volume textures not impemented yet, ignoring!");
}
#endif
/* TODO: It should only be possible to create textures for formats
* that are reported as supported. */
{
return WINED3DERR_INVALIDCALL;
}
{
return WINED3DERR_INVALIDCALL;
}
/* Calculate levels for mip mapping. */
{
{
WARN("No mipmap generation support, returning D3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
if (levels > 1)
{
WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
levels = 1;
}
else if (!levels)
{
}
{
pow2_w = 1;
pow2_w <<= 1;
pow2_h = 1;
pow2_h <<= 1;
pow2_d = 1;
pow2_d <<= 1;
{
{
WARN("Creating a scratch NPOT volume texture despite lack of HW support.\n");
}
else
{
WARN("Attempted to create a NPOT volume texture (%u, %u, %u) without GL support.\n",
return WINED3DERR_INVALIDCALL;
}
}
}
#ifdef VBOX_WITH_WDDM
, shared_handle, pavClientMem)))
#else
#endif
{
return hr;
}
/* Generate all the surfaces. */
for (i = 0; i < texture->level_count; ++i)
{
struct wined3d_volume *volume;
/* Create the volume. */
#ifdef VBOX_WITH_WDDM
#endif
);
{
return hr;
}
/* Set its container to this texture. */
/* Calculate the next mipmap level. */
}
return WINED3D_OK;
}
HRESULT CDECL wined3d_texture_create_2d(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
struct wined3d_texture **texture
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
struct wined3d_texture *object;
TRACE("device %p, desc %p, level_count %u, surface_flags %#x, parent %p, parent_ops %p, texture %p.\n",
if (!object)
{
return WINED3DERR_OUTOFVIDEOMEMORY;
}
#ifdef VBOX_WITH_WDDM
, shared_handle, pavClientMem)))
#else
if (FAILED(hr = texture_init(object, desc, level_count, surface_flags, device, parent, parent_ops)))
#endif
{
return hr;
}
return WINED3D_OK;
}
HRESULT CDECL wined3d_texture_create_3d(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
UINT level_count, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_texture **texture
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
struct wined3d_texture *object;
TRACE("device %p, desc %p, level_count %u, parent %p, parent_ops %p, texture %p.\n",
if (!object)
{
return WINED3DERR_OUTOFVIDEOMEMORY;
}
#ifdef VBOX_WITH_WDDM
, shared_handle, pavClientMem)))
#else
#endif
{
return hr;
}
return WINED3D_OK;
}
HRESULT CDECL wined3d_texture_create_cube(struct wined3d_device *device, const struct wined3d_resource_desc *desc,
struct wined3d_texture **texture
#ifdef VBOX_WITH_WDDM
, void **pavClientMem
#endif
)
{
struct wined3d_texture *object;
TRACE("device %p, desc %p, level_count %u, surface_flags %#x, parent %p, parent_ops %p, texture %p.\n",
if (!object)
{
return WINED3DERR_OUTOFVIDEOMEMORY;
}
#ifdef VBOX_WITH_WDDM
if (FAILED(hr = cubetexture_init(object, desc, level_count, surface_flags, device, parent, parent_ops
, shared_handle, pavClientMem)))
#else
if (FAILED(hr = cubetexture_init(object, desc, level_count, surface_flags, device, parent, parent_ops)))
#endif
{
return hr;
}
return WINED3D_OK;
}
#ifdef VBOX_WITH_WDDM
HRESULT CDECL wined3d_device_blt_voltex(struct wined3d_device *device, struct wined3d_texture *src, struct wined3d_texture *dst,
{
unsigned int level_count, i;
struct wined3d_volume *src_volume;
struct wined3d_volume *dst_volume;
{
ERR("Source and destination have different level counts, returning WINED3DERR_INVALIDCALL.\n");
return WINED3DERR_INVALIDCALL;
}
for (i = 0; i < level_count; ++i)
{
if (pSrcBoxArg)
{
}
else
{
}
if (pDstPoin3D)
{
}
else
{
}
{
return hr;
}
}
return hr;
}
#endif