/* Context activation is done by the caller. */ HRESULT basetexture_bind(IWineD3DBaseTexture *iface, BOOL srgb, BOOL *set_surface_desc) { IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface; HRESULT hr = WINED3D_OK; UINT textureDimensions; BOOL isNewTexture = FALSE; struct gl_texture *gl_tex; TRACE("(%p) : About to bind texture\n", This); This->baseTexture.is_srgb = srgb; /* SRGB mode cache for PreLoad calls outside drawprim */ if(srgb) { gl_tex = &This->baseTexture.texture_srgb; } else { gl_tex = &This->baseTexture.texture_rgb; } textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface); ENTER_GL(); /* Generate a texture name if we don't already have one */ if (gl_tex->name == 0) { *set_surface_desc = TRUE; #ifdef VBOX_WITH_WDDM if (VBOXSHRC_IS_SHARED_OPENED(This)) { gl_tex->name = VBOXSHRC_GET_SHAREHANDLE(This); } else #endif { glGenTextures(1, &gl_tex->name); #ifdef VBOX_WITH_WDDM if (VBOXSHRC_IS_SHARED(This)) { VBOXSHRC_SET_SHAREHANDLE(This, gl_tex->name); } #endif } checkGLcall("glGenTextures"); TRACE("Generated texture %d\n", gl_tex->name); if (This->resource.pool == WINED3DPOOL_DEFAULT) { /* Tell opengl to try and keep this texture in video ram (well mostly) */ GLclampf tmp; tmp = 0.9f; glPrioritizeTextures(1, &gl_tex->name, &tmp); } /* Initialise the state of the texture object to the openGL defaults, not the directx defaults */ gl_tex->states[WINED3DTEXSTA_ADDRESSU] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_ADDRESSV] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_ADDRESSW] = WINED3DTADDRESS_WRAP; gl_tex->states[WINED3DTEXSTA_BORDERCOLOR] = 0; gl_tex->states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_LINEAR; gl_tex->states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT; /* GL_NEAREST_MIPMAP_LINEAR */ gl_tex->states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_LINEAR; /* GL_NEAREST_MIPMAP_LINEAR */ gl_tex->states[WINED3DTEXSTA_MAXMIPLEVEL] = 0; gl_tex->states[WINED3DTEXSTA_MAXANISOTROPY] = 1; gl_tex->states[WINED3DTEXSTA_SRGBTEXTURE] = 0; gl_tex->states[WINED3DTEXSTA_ELEMENTINDEX] = 0; gl_tex->states[WINED3DTEXSTA_DMAPOFFSET] = 0; gl_tex->states[WINED3DTEXSTA_TSSADDRESSW] = WINED3DTADDRESS_WRAP; IWineD3DBaseTexture_SetDirty(iface, TRUE); isNewTexture = TRUE; if(This->resource.usage & WINED3DUSAGE_AUTOGENMIPMAP) { /* 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 */ glBindTexture(textureDimensions, gl_tex->name); checkGLcall("glBindTexture"); glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); checkGLcall("glTexParameteri(textureDimensions, GL_GENERATE_MIPMAP_SGIS, GL_TRUE)"); } } else { *set_surface_desc = FALSE; } /* Bind the texture */ if (gl_tex->name != 0) { glBindTexture(textureDimensions, gl_tex->name); checkGLcall("glBindTexture"); if (isNewTexture) { /* For a new texture we have to set the textures levels after binding the texture. * In theory this is all we should ever have to do, but because ATI's drivers are broken, we * also need to set the texture dimensions before the texture is set * 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 * (ie, do not care for cond_np2 here, just look for GL_TEXTURE_RECTANGLE_ARB) */ if(textureDimensions != GL_TEXTURE_RECTANGLE_ARB) { TRACE("Setting GL_TEXTURE_MAX_LEVEL to %d\n", This->baseTexture.levels - 1); glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels - 1); checkGLcall("glTexParameteri(textureDimensions, GL_TEXTURE_MAX_LEVEL, This->baseTexture.levels)"); } if(textureDimensions==GL_TEXTURE_CUBE_MAP_ARB) { /* Cubemaps are always set to clamp, regardless of the sampler state. */ glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(textureDimensions, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } } } else { /* this only happened if we've run out of openGL textures */ WARN("This texture doesn't have an openGL texture assigned to it\n"); hr = WINED3DERR_INVALIDCALL; } LEAVE_GL(); return hr; }
HRESULT texture_init(IWineD3DTextureImpl *texture, UINT width, UINT height, UINT levels, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format, WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops #ifdef VBOX_WITH_WDDM , HANDLE *shared_handle , void **pavClientMem #endif ) { const struct wined3d_gl_info *gl_info = &device->adapter->gl_info; const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info); UINT pow2_width, pow2_height; UINT tmp_w, tmp_h; unsigned int i; HRESULT hr; /* TODO: It should only be possible to create textures for formats * that are reported as supported. */ if (WINED3DFMT_UNKNOWN >= format) { WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN.\n", texture); return WINED3DERR_INVALIDCALL; } /* Non-power2 support. */ if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO]) { pow2_width = width; pow2_height = height; } else { /* Find the nearest pow2 match. */ pow2_width = pow2_height = 1; while (pow2_width < width) pow2_width <<= 1; while (pow2_height < height) pow2_height <<= 1; if (pow2_width != width || pow2_height != height) { if (levels > 1) { WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support.\n"); return WINED3DERR_INVALIDCALL; } levels = 1; } } /* Calculate levels for mip mapping. */ if (usage & WINED3DUSAGE_AUTOGENMIPMAP) { if (!gl_info->supported[SGIS_GENERATE_MIPMAP]) { 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) { levels = wined3d_log2i(max(width, height)) + 1; TRACE("Calculated levels = %u.\n", levels); } texture->lpVtbl = &IWineD3DTexture_Vtbl; hr = basetexture_init((IWineD3DBaseTextureImpl *)texture, levels, WINED3DRTYPE_TEXTURE, device, 0, usage, format_desc, pool, parent, parent_ops #ifdef VBOX_WITH_WDDM , shared_handle, pavClientMem #endif ); if (FAILED(hr)) { WARN("Failed to initialize basetexture, returning %#x.\n", hr); 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. */ if (gl_info->supported[WINE_NORMALIZED_TEXRECT] && (width != pow2_width || height != pow2_height)) { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = TRUE; texture->baseTexture.minMipLookup = minMipLookup_noFilter; } else if (gl_info->supported[ARB_TEXTURE_RECTANGLE] && (width != pow2_width || height != pow2_height) && !(format_desc->format == WINED3DFMT_P8_UINT && gl_info->supported[EXT_PALETTED_TEXTURE] && wined3d_settings.rendertargetlock_mode == RTL_READTEX)) { if ((width != 1) || (height != 1)) texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (float)width; texture->baseTexture.pow2Matrix[5] = (float)height; texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_RECTANGLE_ARB; texture->cond_np2 = TRUE; if(texture->resource.format_desc->Flags & WINED3DFMT_FLAG_FILTERING) { texture->baseTexture.minMipLookup = minMipLookup_noMip; } else { texture->baseTexture.minMipLookup = minMipLookup_noFilter; } } else { if ((width != pow2_width) || (height != pow2_height)) { texture->baseTexture.pow2Matrix_identity = FALSE; texture->baseTexture.pow2Matrix[0] = (((float)width) / ((float)pow2_width)); texture->baseTexture.pow2Matrix[5] = (((float)height) / ((float)pow2_height)); } else { texture->baseTexture.pow2Matrix[0] = 1.0f; texture->baseTexture.pow2Matrix[5] = 1.0f; } texture->baseTexture.pow2Matrix[10] = 1.0f; texture->baseTexture.pow2Matrix[15] = 1.0f; texture->target = GL_TEXTURE_2D; texture->cond_np2 = FALSE; } TRACE("xf(%f) yf(%f)\n", texture->baseTexture.pow2Matrix[0], texture->baseTexture.pow2Matrix[5]); /* Generate all the surfaces. */ tmp_w = width; tmp_h = height; for (i = 0; i < texture->baseTexture.levels; ++i) { #ifdef VBOX_WITH_WDDM /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i] , NULL /* <- we first create a surface in an everage "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 */ , pavClientMem ? pavClientMem[i] : NULL); #else /* Use the callback to create the texture surface. */ hr = IWineD3DDeviceParent_CreateSurface(device->device_parent, parent, tmp_w, tmp_h, format_desc->format, usage, pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &texture->surfaces[i]); #endif if (FAILED(hr)) { FIXME("Failed to create surface %p, hr %#x\n", texture, hr); texture->surfaces[i] = NULL; texture_cleanup(texture); return hr; } IWineD3DSurface_SetContainer(texture->surfaces[i], (IWineD3DBase *)texture); TRACE("Created surface level %u @ %p.\n", i, texture->surfaces[i]); surface_set_texture_target(texture->surfaces[i], texture->target); /* Calculate the next mipmap level. */ tmp_w = max(1, tmp_w >> 1); tmp_h = max(1, tmp_h >> 1); } texture->baseTexture.internal_preload = texture_internal_preload; #ifdef VBOX_WITH_WDDM if (VBOXSHRC_IS_SHARED(texture)) { Assert(shared_handle); for (i = 0; i < texture->baseTexture.levels; ++i) { VBOXSHRC_COPY_SHAREDATA((IWineD3DSurfaceImpl*)texture->surfaces[i], texture); } #ifdef DEBUG for (i = 0; i < texture->baseTexture.levels; ++i) { Assert(!((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name); } #endif for (i = 0; i < texture->baseTexture.levels; ++i) { if (!VBOXSHRC_IS_SHARED_OPENED(texture)) { IWineD3DSurface_LoadLocation(texture->surfaces[i], SFLAG_INTEXTURE, NULL); Assert(!(*shared_handle)); *shared_handle = VBOXSHRC_GET_SHAREHANDLE(texture); } else { surface_setup_location_onopen((IWineD3DSurfaceImpl*)texture->surfaces[i]); Assert(*shared_handle); Assert(*shared_handle == VBOXSHRC_GET_SHAREHANDLE(texture)); } } #ifdef DEBUG for (i = 0; i < texture->baseTexture.levels; ++i) { Assert((GLuint)(*shared_handle) == ((IWineD3DSurfaceImpl*)texture->surfaces[i])->texture_name); } #endif if (!VBOXSHRC_IS_SHARED_OPENED(texture)) { struct wined3d_context * context; Assert(!device->isInDraw); /* flush to ensure the texture is allocated before it is used by another * process opening it */ context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD); if (context->valid) { wglFlush(); } else { ERR("invalid context!"); } context_release(context); } } else { Assert(!shared_handle); } #endif return WINED3D_OK; }