public Texture Get(TextureStateStruct* TextureState, ClutStateStruct* ClutState) { Texture Texture; //GC.Collect(); bool Swizzled = TextureState->Swizzled; uint TextureAddress = TextureState->Mipmap0.Address; uint ClutAddress = ClutState->Address; var ClutFormat = ClutState->PixelFormat; var ClutStart = ClutState->Start; var ClutDataStart = PixelFormatDecoder.GetPixelsSize(ClutFormat, ClutStart); ulong Hash1 = TextureAddress | (ulong)((ClutAddress + ClutDataStart) << 32); bool Recheck = false; if (Cache.TryGetValue(Hash1, out Texture)) { if (Texture.RecheckTimestamp != RecheckTimestamp) { Recheck = true; } } else { Recheck = true; } if (Recheck) { //Console.Write("."); //Console.WriteLine("{0:X}", ClutAddress); var TexturePointer = (byte*)PspMemory.PspAddressToPointerSafe(TextureAddress); var ClutPointer = (byte *)PspMemory.PspAddressToPointerSafe(ClutAddress); var TextureFormat = TextureState->PixelFormat; //var Width = TextureState->Mipmap0.TextureWidth; int BufferWidth = TextureState->Mipmap0.BufferWidth; var Height = TextureState->Mipmap0.TextureHeight; var TextureDataSize = PixelFormatDecoder.GetPixelsSize(TextureFormat, BufferWidth * Height); if (ClutState->NumberOfColors > 256) { ClutState->NumberOfColors = 256; } var ClutDataSize = PixelFormatDecoder.GetPixelsSize(ClutFormat, ClutState->NumberOfColors); var ClutCount = ClutState->NumberOfColors; var ClutShift = ClutState->Shift; var ClutMask = ClutState->Mask; //Console.WriteLine(TextureFormat); if (TextureDataSize > 2048 * 2048 * 4) { Console.Error.WriteLine("UPDATE_TEXTURE(TEX={0},CLUT={1}:{2}:{3}:{4}:0x{5:X},SIZE={6}x{7},{8},Swizzled={9})", TextureFormat, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, BufferWidth, Height, BufferWidth, Swizzled); Console.Error.WriteLine("Invalid TEXTURE!"); return new Texture(); } TextureCacheKey TextureCacheKey = new TextureCacheKey() { TextureAddress = TextureAddress, TextureFormat = TextureFormat, TextureHash = FastHash((uint*)TexturePointer, TextureDataSize), ClutHash = FastHash((uint*)&(ClutPointer[ClutDataStart]), ClutDataSize), ClutAddress = ClutAddress, ClutFormat = ClutFormat, ClutStart = ClutStart, ClutShift = ClutShift, ClutMask = ClutMask, Swizzled = Swizzled, }; if (Texture == null || (!Texture.TextureCacheKey.Equals(TextureCacheKey))) { #if DEBUG_TEXTURE_CACHE string TextureName = "texture_" + TextureCacheKey.TextureHash + "_" + TextureCacheKey.ClutHash + "_" + TextureFormat + "_" + ClutFormat + "_" + BufferWidth + "x" + Height; Console.Error.WriteLine("UPDATE_TEXTURE(TEX={0},CLUT={1}:{2}:{3}:{4}:0x{5:X},SIZE={6}x{7},{8},Swizzled={9})", TextureFormat, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, BufferWidth, Height, BufferWidth, Swizzled); #endif Texture = new Texture(); Texture.TextureCacheKey = TextureCacheKey; { fixed (PixelFormatDecoder.OutputPixel* TexturePixelsPointer = DecodedTextureBuffer) { if (Swizzled) { fixed (byte* SwizzlingBufferPointer = SwizzlingBuffer) { Marshal.Copy(new IntPtr(TexturePointer), SwizzlingBuffer, 0, TextureDataSize); PixelFormatDecoder.UnswizzleInline(TextureFormat, (void*)SwizzlingBufferPointer, BufferWidth, Height); PixelFormatDecoder.Decode( TextureFormat, (void*)SwizzlingBufferPointer, TexturePixelsPointer, BufferWidth, Height, ClutPointer, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask ); } } else { PixelFormatDecoder.Decode( TextureFormat, (void*)TexturePointer, TexturePixelsPointer, BufferWidth, Height, ClutPointer, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask ); } #if DEBUG_TEXTURE_CACHE var Bitmap = new Bitmap(BufferWidth, Height); BitmapUtils.TransferChannelsDataInterleaved( Bitmap.GetFullRectangle(), Bitmap, (byte*)TexturePixelsPointer, BitmapUtils.Direction.FromDataToBitmap, BitmapChannel.Red, BitmapChannel.Green, BitmapChannel.Blue, BitmapChannel.Alpha ); Bitmap.Save(TextureName + ".png"); #endif Texture.SetData(TexturePixelsPointer, BufferWidth, Height); } } if (Cache.ContainsKey(Hash1)) { Cache[Hash1].Dispose(); } Cache[Hash1] = Texture; } } Texture.RecheckTimestamp = RecheckTimestamp; return Texture; }
public static unsafe void TransferChannelsDataLinear(Rectangle Rectangle, Bitmap Bitmap, byte[] NewData, Direction Direction, params BitmapChannel[] Channels) { int WidthHeight = Bitmap.Width * Bitmap.Height; var FullRectangle = Bitmap.GetFullRectangle(); if (!FullRectangle.Contains(Rectangle.Location)) throw(new InvalidProgramException()); if (!FullRectangle.Contains(Rectangle.Location + Rectangle.Size - new Size(1, 1))) throw (new InvalidProgramException()); int NumberOfChannels = 1; foreach (var Channel in Channels) { if (Channel != BitmapChannel.Indexed) { NumberOfChannels = 4; break; } } Bitmap.LockBitsUnlock((NumberOfChannels == 1) ? PixelFormat.Format8bppIndexed : PixelFormat.Format32bppArgb, (BitmapData) => { byte* BitmapDataScan0 = (byte*)BitmapData.Scan0.ToPointer(); int Width = Bitmap.Width; int Height = Bitmap.Height; int Stride = BitmapData.Stride; if (NumberOfChannels == 1) { Stride = Width; } int RectangleTop = Rectangle.Top; int RectangleBottom = Rectangle.Bottom; int RectangleLeft = Rectangle.Left; int RectangleRight = Rectangle.Right; fixed (byte* OutputPtrStart = &NewData[0]) { byte* OutputPtr = OutputPtrStart; foreach (var Channel in Channels) { for (int y = RectangleTop; y < RectangleBottom; y++) { byte* InputPtr = BitmapDataScan0 + Stride * y; if (NumberOfChannels != 1) { InputPtr = InputPtr + (int)Channel; } InputPtr += NumberOfChannels * RectangleLeft; for (int x = RectangleLeft; x < RectangleRight; x++) { if (Direction == Direction.FromBitmapToData) { *OutputPtr = *InputPtr; } else { *InputPtr = * OutputPtr; } OutputPtr++; InputPtr += NumberOfChannels; } } } } }); }
public static unsafe void TransferChannelsDataLinear(Bitmap Bitmap, byte[] NewData, Direction Direction, params BitmapChannel[] Channels) { TransferChannelsDataLinear(Bitmap.GetFullRectangle(), Bitmap, NewData, Direction, Channels); }
private void SaveFrameBuffer(GpuStateStruct* GpuState, string FileName) { var GlPixelFormat = GlPixelFormatList[(int)GuPixelFormats.RGBA_8888]; int Width = (int)GpuState->DrawBufferState.Width; if (Width == 0) Width = 512; int Height = 272; int ScanWidth = PixelFormatDecoder.GetPixelsSize(GlPixelFormat.GuPixelFormat, Width); int PixelSize = PixelFormatDecoder.GetPixelsSize(GlPixelFormat.GuPixelFormat, 1); if (Width == 0) Width = 512; GL.PixelStore(PixelStoreParameter.PackAlignment, PixelSize); var FB = new Bitmap(Width, Height); var Data = new byte[Width * Height * 4]; fixed (byte* DataPtr = Data) { GL.ReadPixels(0, 0, Width, Height, PixelFormat.Rgba, GlPixelFormat.OpenglPixelType, new IntPtr(DataPtr)); BitmapUtils.TransferChannelsDataInterleaved( FB.GetFullRectangle(), FB, DataPtr, BitmapUtils.Direction.FromDataToBitmap, BitmapChannel.Red, BitmapChannel.Green, BitmapChannel.Blue, BitmapChannel.Alpha ); } FB.Save(FileName); }
public Texture Get(GpuStateStruct *GpuState) { var TextureMappingState = &GpuState->TextureMappingState; var ClutState = &TextureMappingState->ClutState; var TextureState = &TextureMappingState->TextureState; Texture Texture; //GC.Collect(); bool Swizzled = TextureState->Swizzled; uint TextureAddress = TextureState->Mipmap0.Address; uint ClutAddress = ClutState->Address; var ClutFormat = ClutState->PixelFormat; var ClutStart = ClutState->Start; var ClutDataStart = PixelFormatDecoder.GetPixelsSize(ClutFormat, ClutStart); ulong Hash1 = TextureAddress | (ulong)((ClutAddress + ClutDataStart) << 32); bool Recheck = false; if (Cache.TryGetValue(Hash1, out Texture)) { if (Texture.RecheckTimestamp != RecheckTimestamp) { Recheck = true; } } else { Recheck = true; } if (Recheck) { //Console.Write("."); //Console.WriteLine("{0:X}", ClutAddress); var TexturePointer = (byte*)PspMemory.PspAddressToPointerSafe(TextureAddress); var ClutPointer = (byte *)PspMemory.PspAddressToPointerSafe(ClutAddress); var TextureFormat = TextureState->PixelFormat; //var Width = TextureState->Mipmap0.TextureWidth; int BufferWidth = TextureState->Mipmap0.BufferWidth; var Height = TextureState->Mipmap0.TextureHeight; var TextureDataSize = PixelFormatDecoder.GetPixelsSize(TextureFormat, BufferWidth * Height); if (ClutState->NumberOfColors > 256) { ClutState->NumberOfColors = 256; } var ClutDataSize = PixelFormatDecoder.GetPixelsSize(ClutFormat, ClutState->NumberOfColors); var ClutCount = ClutState->NumberOfColors; var ClutShift = ClutState->Shift; var ClutMask = ClutState->Mask; //Console.WriteLine(TextureFormat); if (!PspMemory.IsAddressValid((uint)(TextureAddress + TextureDataSize - 1))) { Console.Error.WriteLine("Invalid TEXTURE!"); return new Texture(OpenglGpuImpl); } if (TextureDataSize > 2048 * 2048 * 4) { Console.Error.WriteLine("UPDATE_TEXTURE(TEX={0},CLUT={1}:{2}:{3}:{4}:0x{5:X},SIZE={6}x{7},{8},Swizzled={9})", TextureFormat, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, BufferWidth, Height, BufferWidth, Swizzled); Console.Error.WriteLine("Invalid TEXTURE!"); return new Texture(OpenglGpuImpl); } //Console.WriteLine("TextureAddress=0x{0:X}, TextureDataSize=0x{1:X}", TextureAddress, TextureDataSize); TextureCacheKey TextureCacheKey = new TextureCacheKey() { TextureAddress = TextureAddress, TextureFormat = TextureFormat, TextureHash = FastHash((uint*)TexturePointer, TextureDataSize), ClutHash = FastHash((uint*)&(ClutPointer[ClutDataStart]), ClutDataSize), ClutAddress = ClutAddress, ClutFormat = ClutFormat, ClutStart = ClutStart, ClutShift = ClutShift, ClutMask = ClutMask, Swizzled = Swizzled, ColorTestEnabled = GpuState->ColorTestState.Enabled, ColorTestRef = GpuState->ColorTestState.Ref, ColorTestMask = GpuState->ColorTestState.Mask, ColorTestFunction = GpuState->ColorTestState.Function, }; if (Texture == null || (!Texture.TextureCacheKey.Equals(TextureCacheKey))) { string TextureName = "texture_" + TextureCacheKey.TextureHash + "_" + TextureCacheKey.ClutHash + "_" + TextureFormat + "_" + ClutFormat + "_" + BufferWidth + "x" + Height + "_" + Swizzled; #if DEBUG_TEXTURE_CACHE Console.Error.WriteLine("UPDATE_TEXTURE(TEX={0},CLUT={1}:{2}:{3}:{4}:0x{5:X},SIZE={6}x{7},{8},Swizzled={9})", TextureFormat, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, BufferWidth, Height, BufferWidth, Swizzled); #endif Texture = new Texture(OpenglGpuImpl); Texture.TextureCacheKey = TextureCacheKey; { //int TextureWidth = Math.Max(BufferWidth, Height); //int TextureHeight = Math.Max(BufferWidth, Height); int TextureWidth = BufferWidth; int TextureHeight = Height; int TextureWidthHeight = TextureWidth * TextureHeight; fixed (OutputPixel* TexturePixelsPointer = DecodedTextureBuffer) { if (Swizzled) { fixed (byte* SwizzlingBufferPointer = SwizzlingBuffer) { Marshal.Copy(new IntPtr(TexturePointer), SwizzlingBuffer, 0, TextureDataSize); PixelFormatDecoder.UnswizzleInline(TextureFormat, (void*)SwizzlingBufferPointer, BufferWidth, Height); PixelFormatDecoder.Decode( TextureFormat, (void*)SwizzlingBufferPointer, TexturePixelsPointer, BufferWidth, Height, ClutPointer, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, StrideWidth: PixelFormatDecoder.GetPixelsSize(TextureFormat, TextureWidth) ); } } else { PixelFormatDecoder.Decode( TextureFormat, (void*)TexturePointer, TexturePixelsPointer, BufferWidth, Height, ClutPointer, ClutFormat, ClutCount, ClutStart, ClutShift, ClutMask, StrideWidth: PixelFormatDecoder.GetPixelsSize(TextureFormat, TextureWidth) ); } if (TextureCacheKey.ColorTestEnabled) { byte EqualValue, NotEqualValue; switch (TextureCacheKey.ColorTestFunction) { case ColorTestFunctionEnum.GU_ALWAYS: EqualValue = 0xFF; NotEqualValue = 0xFF; break; case ColorTestFunctionEnum.GU_NEVER: EqualValue = 0x00; NotEqualValue = 0x00; break; case ColorTestFunctionEnum.GU_EQUAL: EqualValue = 0xFF; NotEqualValue = 0x00; break; case ColorTestFunctionEnum.GU_NOTEQUAL: EqualValue = 0x00; NotEqualValue = 0xFF; break; default: throw(new NotImplementedException()); } ConsoleUtils.SaveRestoreConsoleState(() => { Console.BackgroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Yellow; Console.Error.WriteLine("{0} : {1}, {2} : ref:{3} : mask:{4}", TextureCacheKey.ColorTestFunction, EqualValue, NotEqualValue, TextureCacheKey.ColorTestRef, TextureCacheKey.ColorTestMask); }); for (int n = 0; n < TextureWidthHeight; n++) { if ((TexturePixelsPointer[n] & TextureCacheKey.ColorTestMask).Equals((TextureCacheKey.ColorTestRef & TextureCacheKey.ColorTestMask))) { TexturePixelsPointer[n].A = EqualValue; } else { TexturePixelsPointer[n].A = NotEqualValue; } if (TexturePixelsPointer[n].A == 0) { //Console.Write("yup!"); } } } /* var Bitmap = new Bitmap(BufferWidth, Height); BitmapUtils.TransferChannelsDataInterleaved( Bitmap.GetFullRectangle(), Bitmap, (byte*)TexturePixelsPointer, BitmapUtils.Direction.FromDataToBitmap, BitmapChannel.Red, BitmapChannel.Green, BitmapChannel.Blue, BitmapChannel.Alpha ); Bitmap.Save(TextureName + ".png"); */ #if DEBUG_TEXTURE_CACHE var Bitmap = new Bitmap(BufferWidth, Height); BitmapUtils.TransferChannelsDataInterleaved( Bitmap.GetFullRectangle(), Bitmap, (byte*)TexturePixelsPointer, BitmapUtils.Direction.FromDataToBitmap, BitmapChannel.Red, BitmapChannel.Green, BitmapChannel.Blue, BitmapChannel.Alpha ); Bitmap.Save(TextureName + ".png"); #endif var Result = Texture.SetData(TexturePixelsPointer, TextureWidth, TextureHeight); #if DEBUG_TEXTURE_CACHE if (!Result || Texture.TextureId == 0) { var Bitmap2 = new Bitmap(BufferWidth, Height); BitmapUtils.TransferChannelsDataInterleaved( Bitmap2.GetFullRectangle(), Bitmap2, (byte*)TexturePixelsPointer, BitmapUtils.Direction.FromDataToBitmap, BitmapChannel.Red, BitmapChannel.Green, BitmapChannel.Blue, BitmapChannel.Alpha ); string TextureName2 = @"C:\projects\csharp\cspspemu\__invalid_texture_" + TextureCacheKey.TextureHash + "_" + TextureCacheKey.ClutHash + "_" + TextureFormat + "_" + ClutFormat + "_" + BufferWidth + "x" + Height; Bitmap.Save(TextureName2 + ".png"); } #endif } } if (Cache.ContainsKey(Hash1)) { Cache[Hash1].Dispose(); } Cache[Hash1] = Texture; } } Texture.RecheckTimestamp = RecheckTimestamp; return Texture; }
public void Save(string File) { var Bitmap = new Bitmap(this.Width, this.Height); fixed (OutputPixel* DataPtr = Data) { BitmapUtils.TransferChannelsDataInterleaved( Bitmap.GetFullRectangle(), Bitmap, (byte*)DataPtr, BitmapUtils.Direction.FromDataToBitmap, BitmapChannel.Red, BitmapChannel.Green, BitmapChannel.Blue, BitmapChannel.Alpha ); } Bitmap.Save(File); }