public static int GetSize(GalImage image) { ImageDescriptor desc = GetImageDescriptor(image.Format); int componentCount = GetCoordsCountTextureTarget(image.TextureTarget); if (IsArray(image.TextureTarget)) { componentCount--; } int width = DivRoundUp(image.Width, desc.BlockWidth); int height = DivRoundUp(image.Height, desc.BlockHeight); int depth = DivRoundUp(image.Depth, desc.BlockDepth); switch (componentCount) { case 1: return(desc.BytesPerPixel * width * image.LayerCount); case 2: return(desc.BytesPerPixel * width * height * image.LayerCount); case 3: return(desc.BytesPerPixel * width * height * depth * image.LayerCount); default: throw new InvalidOperationException($"Invalid component count: {componentCount}"); } }
private void SetZeta(NvGpuVmm Vmm) { long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); int ZetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat); int BlockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions); int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); //? bool ZetaEnable = ReadRegisterBool(NvGpuEngine3dReg.ZetaEnable); if (VA == 0 || ZetaFormat == 0 || !ZetaEnable) { Gpu.Renderer.RenderTarget.UnbindZeta(); return; } long Key = Vmm.GetPhysicalAddress(VA); int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert); GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat); GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image); }
public void Create(long Key, int Size, GalImage Image) { int Handle = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size); if (ImageUtils.IsCompressed(Image.Format)) { throw new InvalidOperationException("Surfaces with compressed formats are not supported!"); } (PixelInternalFormat InternalFmt, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); GL.TexImage2D( TextureTarget.Texture2D, Level, InternalFmt, Image.Width, Image.Height, Border, Format, Type, IntPtr.Zero); }
private void SetZeta(NvGpuVmm Vmm) { long ZA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); int Format = ReadRegister(NvGpuEngine3dReg.ZetaFormat); bool ZetaEnable = (ReadRegister(NvGpuEngine3dReg.ZetaEnable) & 1) != 0; if (ZA == 0 || Format == 0 || !ZetaEnable) { Gpu.Renderer.FrameBuffer.UnbindZeta(); return; } long Key = Vmm.GetPhysicalAddress(ZA); int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert); GalImageFormat ImageFormat = ImageFormatConverter.ConvertZeta((GalZetaFormat)Format); GalImage Image = new GalImage(Width, Height, ImageFormat); long Size = TextureHelper.GetTextureSize(Image); Gpu.Renderer.Texture.CreateFb(Key, Size, Image); Gpu.Renderer.FrameBuffer.BindZeta(Key); }
public static void WriteTexture(NvGpuVmm vmm, GalImage image, long position, byte[] data) { ISwizzle swizzle = TextureHelper.GetSwizzle(image); ImageDescriptor desc = GetImageDescriptor(image.Format); (int width, int height, int depth) = GetImageSizeInBlocks(image); int bytesPerPixel = desc.BytesPerPixel; int inOffs = 0; for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { long offset = (uint)swizzle.GetSwizzleOffset(x, y, z); vmm.Memory.WriteBytes(position + offset, data, inOffs, bytesPerPixel); inOffs += bytesPerPixel; } } } }
public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); return(DivRoundUp(Image.Width, Desc.BlockWidth), DivRoundUp(Image.Height, Desc.BlockHeight)); }
private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) { long Size = ImageUtils.GetSize(NewImage); bool SkipCheck = false; if (ImageTypes.TryGetValue(Position, out ImageType OldType)) { if (OldType == ImageType.ColorBuffer || OldType == ImageType.ZetaBuffer) { //Avoid data destruction MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture); SkipCheck = true; } } if (SkipCheck || !MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture)) { if (TryReuse(Vmm, Position, NewImage)) { return; } } byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position); Gpu.Renderer.Texture.Create(Position, Data, NewImage); }
public static ISwizzle GetSwizzle(GalImage image) { int blockWidth = ImageUtils.GetBlockWidth(image.Format); int blockHeight = ImageUtils.GetBlockHeight(image.Format); int blockDepth = ImageUtils.GetBlockDepth(image.Format); int bytesPerPixel = ImageUtils.GetBytesPerPixel(image.Format); int width = BitUtils.DivRoundUp(image.Width, blockWidth); int height = BitUtils.DivRoundUp(image.Height, blockHeight); int depth = BitUtils.DivRoundUp(image.Depth, blockDepth); if (image.Layout == GalMemoryLayout.BlockLinear) { int alignMask = image.TileWidth * (64 / bytesPerPixel) - 1; width = (width + alignMask) & ~alignMask; return(new BlockLinearSwizzle( width, height, depth, image.GobBlockHeight, image.GobBlockDepth, bytesPerPixel)); } else { return(new LinearSwizzle(image.Pitch, bytesPerPixel, width, height)); } }
private void PrepareSendTexture(NvGpuVmm vmm, long position, GalImage newImage) { long size = ImageUtils.GetSize(newImage); bool skipCheck = false; if (_imageTypes.TryGetValue(position, out ImageType oldType)) { if (oldType == ImageType.ColorBuffer || oldType == ImageType.ZetaBuffer) { //Avoid data destruction MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture); skipCheck = true; } } if (skipCheck || !MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture)) { if (TryReuse(vmm, position, newImage)) { return; } } byte[] data = ImageUtils.ReadTexture(vmm, newImage, position); _gpu.Renderer.Texture.Create(position, data, newImage); }
private void SetZeta(NvGpuVmm vmm) { long va = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); int zetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat); int blockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions); int gobBlockHeight = 1 << ((blockDim >> 4) & 7); GalMemoryLayout layout = (GalMemoryLayout)((blockDim >> 12) & 1); //? bool zetaEnable = ReadRegisterBool(NvGpuEngine3dReg.ZetaEnable); if (va == 0 || zetaFormat == 0 || !zetaEnable) { _gpu.Renderer.RenderTarget.UnbindZeta(); return; } long key = vmm.GetPhysicalAddress(va); int width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); int height = ReadRegister(NvGpuEngine3dReg.ZetaVert); GalImageFormat format = ImageUtils.ConvertZeta((GalZetaFormat)zetaFormat); // TODO: Support non 2D? GalImage image = new GalImage(width, height, 1, 1, 1, gobBlockHeight, 1, layout, format, GalTextureTarget.TwoD); _gpu.ResourceManager.SendZetaBuffer(vmm, key, image); }
public void Create(long Key, byte[] Data, GalImage Image) { int Handle = GL.GenTexture(); GL.BindTexture(TextureTarget.Texture2D, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format)) { InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); GL.CompressedTexImage2D( TextureTarget.Texture2D, Level, InternalFmt, Image.Width, Image.Height, Border, Data.Length, Data); } else { //TODO: Use KHR_texture_compression_astc_hdr when available if (IsAstc(Image.Format)) { int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format); int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format); Data = ASTCDecoder.DecodeToRGBA8888( Data, TextureBlockWidth, TextureBlockHeight, 1, Image.Width, Image.Height, 1); Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask); } (PixelInternalFormat InternalFmt, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); GL.TexImage2D( TextureTarget.Texture2D, Level, InternalFmt, Image.Width, Image.Height, Border, Format, Type, Data); } }
public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage image) { ImageDescriptor desc = GetImageDescriptor(image.Format); return(DivRoundUp(image.Width, desc.BlockWidth), DivRoundUp(image.Height, desc.BlockHeight), DivRoundUp(image.Depth, desc.BlockDepth)); }
private void SetFrameBuffer(NvGpuVmm vmm, int fbIndex) { ProfileConfig profile = Profiles.GPU.Engine3d.SetFrameBuffer; profile.SessionItem = fbIndex.ToString(); Profile.Begin(profile); long va = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + fbIndex * 0x10); int surfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + fbIndex * 0x10); if (va == 0 || surfFormat == 0) { _gpu.Renderer.RenderTarget.UnbindColor(fbIndex); Profile.End(profile); return; } long key = vmm.GetPhysicalAddress(va); int width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + fbIndex * 0x10); int height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + fbIndex * 0x10); int arrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + fbIndex * 0x10); int layerCount = arrayMode & 0xFFFF; int layerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + fbIndex * 0x10); int baseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + fbIndex * 0x10); int blockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + fbIndex * 0x10); int gobBlockHeight = 1 << ((blockDim >> 4) & 7); GalMemoryLayout layout = (GalMemoryLayout)((blockDim >> 12) & 1); float tx = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + fbIndex * 8); float ty = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + fbIndex * 8); float sx = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + fbIndex * 8); float sy = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + fbIndex * 8); _viewportX0 = (int)MathF.Max(0, tx - MathF.Abs(sx)); _viewportY0 = (int)MathF.Max(0, ty - MathF.Abs(sy)); _viewportX1 = (int)(tx + MathF.Abs(sx)); _viewportY1 = (int)(ty + MathF.Abs(sy)); GalImageFormat format = ImageUtils.ConvertSurface((GalSurfaceFormat)surfFormat); GalImage image = new GalImage(width, height, 1, 1, 1, gobBlockHeight, 1, layout, format, GalTextureTarget.TwoD); _gpu.ResourceManager.SendColorBuffer(vmm, key, fbIndex, image); _gpu.Renderer.RenderTarget.SetViewport(fbIndex, _viewportX0, _viewportY0, _viewportX1 - _viewportX0, _viewportY1 - _viewportY0); Profile.End(profile); }
public static int GetLayerOffset(GalImage image, int mipLevel) { if (mipLevel <= 0) { mipLevel = 1; } return(TextureHelper.GetSwizzle(image).GetMipOffset(mipLevel)); }
public static int GetSize(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); int Width = DivRoundUp(Image.Width, Desc.BlockWidth); int Height = DivRoundUp(Image.Height, Desc.BlockHeight); return(Desc.BytesPerPixel * Width * Height); }
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1) { PrepareSendTexture(Vmm, Position, NewImage); if (TexIndex >= 0) { Gpu.Renderer.Texture.Bind(Position, TexIndex, NewImage); } ImageTypes[Position] = ImageType.Texture; }
public void Reinterpret(long key, GalImage newImage) { if (!_texture.TryGetImage(key, out GalImage oldImage)) { return; } if (newImage.Format == oldImage.Format && newImage.Width == oldImage.Width && newImage.Height == oldImage.Height && newImage.Depth == oldImage.Depth && newImage.LayerCount == oldImage.LayerCount && newImage.TextureTarget == oldImage.TextureTarget) { return; } if (_copyPbo == 0) { _copyPbo = GL.GenBuffer(); } GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPbo); // The buffer should be large enough to hold the largest texture. int bufferSize = Math.Max(ImageUtils.GetSize(oldImage), ImageUtils.GetSize(newImage)); GL.BufferData(BufferTarget.PixelPackBuffer, bufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy); if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage)) { throw new InvalidOperationException(); } (_, PixelFormat format, PixelType type) = OglEnumConverter.GetImageFormat(cachedImage.Format); TextureTarget target = ImageUtils.GetTextureTarget(newImage.TextureTarget); GL.BindTexture(target, cachedImage.Handle); GL.GetTexImage(target, 0, format, type, IntPtr.Zero); GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, _copyPbo); GL.PixelStore(PixelStoreParameter.UnpackRowLength, oldImage.Width); _texture.Create(key, ImageUtils.GetSize(newImage), newImage); GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); }
public static byte[] ReadTexture(IMemory memory, GalImage image, long position) { MemoryManager cpuMemory; if (memory is NvGpuVmm vmm) { cpuMemory = vmm.Memory; } else { cpuMemory = (MemoryManager)memory; } ISwizzle swizzle = TextureHelper.GetSwizzle(image); ImageDescriptor desc = GetImageDescriptor(image.Format); (int width, int height, int depth) = GetImageSizeInBlocks(image); int bytesPerPixel = desc.BytesPerPixel; //Note: Each row of the texture needs to be aligned to 4 bytes. int pitch = (width * bytesPerPixel + 3) & ~3; int dataLayerSize = height * pitch * depth; byte[] data = new byte[dataLayerSize * image.LayerCount]; int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1; int layerOffset = GetLayerOffset(image, targetMipLevel); for (int layer = 0; layer < image.LayerCount; layer++) { for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y++) { int outOffs = (dataLayerSize * layer) + y * pitch + (z * width * height * bytesPerPixel); for (int x = 0; x < width; x++) { long offset = (uint)swizzle.GetSwizzleOffset(x, y, z); cpuMemory.ReadBytes(position + (layerOffset * layer) + offset, data, outOffs, bytesPerPixel); outOffs += bytesPerPixel; } } } } return(data); }
private bool TryReuse(NvGpuVmm vmm, long position, GalImage newImage) { if (_gpu.Renderer.Texture.TryGetImage(position, out GalImage cachedImage) && cachedImage.TextureTarget == newImage.TextureTarget && cachedImage.SizeMatches(newImage)) { _gpu.Renderer.RenderTarget.Reinterpret(position, newImage); return(true); } return(false); }
public void CreateFb(long Key, long Size, GalImage Image) { if (!TryGetImage(Key, out ImageHandler CachedImage)) { CachedImage = new ImageHandler(); TextureCache.AddOrUpdate(Key, CachedImage, Size); } CachedImage.EnsureSetup(Image); }
private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage) { if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage)) { Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); return(true); } return(false); }
private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm vmm, int textureHandle) { if (textureHandle == 0) { // FIXME: Some games like puyo puyo will use handles with the value 0. // This is a bug, most likely caused by sync issues. return(0, default(GalImage), default(GalTextureSampler)); } Profile.Begin(Profiles.GPU.Engine3d.UploadTexture); bool linkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc); int ticIndex = (textureHandle >> 0) & 0xfffff; int tscIndex = linkedTsc ? ticIndex : (textureHandle >> 20) & 0xfff; long ticPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); long tscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); ticPosition += ticIndex * 0x20; tscPosition += tscIndex * 0x20; GalImage image = TextureFactory.MakeTexture(vmm, ticPosition); GalTextureSampler sampler = TextureFactory.MakeSampler(_gpu, vmm, tscPosition); long key = vmm.ReadInt64(ticPosition + 4) & 0xffffffffffff; if (image.Layout == GalMemoryLayout.BlockLinear) { key &= ~0x1ffL; } else if (image.Layout == GalMemoryLayout.Pitch) { key &= ~0x1fL; } key = vmm.GetPhysicalAddress(key); if (key == -1) { Profile.End(Profiles.GPU.Engine3d.UploadTexture); // FIXME: Shouldn't ignore invalid addresses. return(0, default(GalImage), default(GalTextureSampler)); } _gpu.ResourceManager.SendTexture(vmm, key, image); Profile.End(Profiles.GPU.Engine3d.UploadTexture); return(key, image, sampler); }
public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition) { int[] Tic = ReadWords(Vmm, TicPosition, 8); GalImageFormat Format = GetImageFormat(Tic); GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7); GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7); GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7); GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7); TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); GalMemoryLayout Layout; if (Swizzle == TextureSwizzle.BlockLinear || Swizzle == TextureSwizzle.BlockLinearColorKey) { Layout = GalMemoryLayout.BlockLinear; } else { Layout = GalMemoryLayout.Pitch; } int BlockHeightLog2 = (Tic[3] >> 3) & 7; int TileWidthLog2 = (Tic[3] >> 10) & 7; int BlockHeight = 1 << BlockHeightLog2; int TileWidth = 1 << TileWidthLog2; int Width = (Tic[4] & 0xffff) + 1; int Height = (Tic[5] & 0xffff) + 1; GalImage Image = new GalImage( Width, Height, TileWidth, BlockHeight, Layout, Format, XSource, YSource, ZSource, WSource); if (Layout == GalMemoryLayout.Pitch) { Image.Pitch = (Tic[3] & 0xffff) << 5; } return(Image); }
public void SendZetaBuffer(NvGpuVmm vmm, long position, GalImage newImage) { long size = (uint)ImageUtils.GetSize(newImage); _imageTypes[position] = ImageType.ZetaBuffer; if (!TryReuse(vmm, position, newImage)) { _gpu.Renderer.Texture.Create(position, (int)size, newImage); } _gpu.Renderer.RenderTarget.BindZeta(position); }
public bool TryGetImage(long Key, out GalImage Image) { if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { Image = CachedImage.Image; return(true); } Image = default(GalImage); return(false); }
public bool TryGetImage(long key, out GalImage image) { if (_textureCache.TryGetValue(key, out ImageHandler cachedImage)) { image = cachedImage.Image; return(true); } image = default(GalImage); return(false); }
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage) { long Size = (uint)ImageUtils.GetSize(NewImage); ImageTypes[Position] = ImageType.ZetaBuffer; if (!TryReuse(Vmm, Position, NewImage)) { Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); } Gpu.Renderer.RenderTarget.BindZeta(Position); }
public void Reinterpret(long Key, GalImage NewImage) { if (!Texture.TryGetImage(Key, out GalImage OldImage)) { return; } if (NewImage.Format == OldImage.Format && NewImage.Width == OldImage.Width && NewImage.Height == OldImage.Height) { return; } if (CopyPBO == 0) { CopyPBO = GL.GenBuffer(); } GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO); //The buffer should be large enough to hold the largest texture. int BufferSize = Math.Max(ImageUtils.GetSize(OldImage), ImageUtils.GetSize(NewImage)); GL.BufferData(BufferTarget.PixelPackBuffer, BufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy); if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage)) { throw new InvalidOperationException(); } (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format); GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); GL.GetTexImage(TextureTarget.Texture2D, 0, Format, Type, IntPtr.Zero); GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO); GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width); Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage); GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); }
private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm Vmm, int TextureHandle) { if (TextureHandle == 0) { //FIXME: Some games like puyo puyo will use handles with the value 0. //This is a bug, most likely caused by sync issues. return(0, default(GalImage), default(GalTextureSampler)); } bool LinkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc); int TicIndex = (TextureHandle >> 0) & 0xfffff; int TscIndex = LinkedTsc ? TicIndex : (TextureHandle >> 20) & 0xfff; long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); TicPosition += TicIndex * 0x20; TscPosition += TscIndex * 0x20; GalImage Image = TextureFactory.MakeTexture(Vmm, TicPosition); GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition); long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; if (Image.Layout == GalMemoryLayout.BlockLinear) { Key &= ~0x1ffL; } else if (Image.Layout == GalMemoryLayout.Pitch) { Key &= ~0x1fL; } Key = Vmm.GetPhysicalAddress(Key); if (Key == -1) { //FIXME: Shouldn't ignore invalid addresses. return(0, default(GalImage), default(GalTextureSampler)); } Gpu.ResourceManager.SendTexture(Vmm, Key, Image); return(Key, Image, Sampler); }
public bool TryGetCachedTexture(long Key, long DataSize, out GalImage Image) { if (TextureCache.TryGetSize(Key, out long Size) && Size == DataSize) { if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) { Image = CachedImage.Image; return(true); } } Image = default(GalImage); return(false); }