Jump to content

Recommended Posts

Posted

Hi all,

 

does anyone know how this works?

I did not manage to find any documentation on how to read from shared memory in lua to be able to send the exported images to another computer/program for display.

 

Any help would be nice ;)

 

basedow

Posted

Here is the C# code I used to decode the shared memory locations.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;

namespace TouchPal
{
   class SharedMemoryBitmap
   {
       private string _sharedMemoryName;
       private IntPtr _fileHandle = IntPtr.Zero;
       private IntPtr _startAddress = IntPtr.Zero;
       private IntPtr _bitmapInfoAddress = IntPtr.Zero;
       private IntPtr _bitmapDataAddress = IntPtr.Zero;

       private const UInt32 SECTION_MAP_READ = 0x0004;

       [structLayout(LayoutKind.Sequential, Pack = 1)]
       public struct BITMAPINFOHEADER
       {
           public uint biSize;
           public int biWidth;
           public int biHeight;
           public ushort biPlanes;
           public ushort biBitCount;
           public uint biCompression;
           public uint biSizeImage;
           public int biXPelsPerMeter;
           public int biYPelsPerMeter;
           public uint biClrUsed;
           public uint biClrImportant;

           public void Init()
           {
               biSize = (uint)Marshal.SizeOf(this);
           }
       }

       [DllImport("kernel32.dll", SetLastError = true)]
       static extern IntPtr OpenFileMapping(
           uint dwDesiredAccess,
           bool bInheritHandle,
           string lpName);

       [DllImport("kernel32.dll", SetLastError = true)]
       static extern IntPtr MapViewOfFile(
           IntPtr hFileMappingObject,
           uint dwDesiredAccess,
           uint dwFileOffsetHigh,
           uint dwFileOffsetLow,
           uint dwNumberOfBytesToMap);

       [DllImport("kernel32.dll", SetLastError = true)]
       [return: MarshalAs(UnmanagedType.Bool)]
       static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);

       [DllImport("kernel32.dll", SetLastError = true)]
       [return: MarshalAs(UnmanagedType.Bool)]
       static extern bool CloseHandle(IntPtr hObject);

       public SharedMemoryBitmap(string sharedMemoryName)
       {
           TouchPal.Debug("Shared Memory Bitmap for " + sharedMemoryName + " created");
           _sharedMemoryName = sharedMemoryName;
       }

       public bool IsDataAvailable
       {
           get
           {
               bool dataAvailable = true;

               if (_fileHandle.Equals(IntPtr.Zero))
               {
                   Open();
               }

               if (_fileHandle.Equals(IntPtr.Zero))
               {
                   dataAvailable = false;
               }
               else if (_startAddress.Equals(IntPtr.Zero))
               {
                   dataAvailable = false;
                   Close();
               }

               return dataAvailable;
           }
       }

       public Image GetImage()
       {
           if (IsDataAvailable)
           {
               Bitmap bitmap = null;
               Int16 identifier = Marshal.ReadInt16(_startAddress);
               if (identifier == 0x4D42)
               {
                   BITMAPINFOHEADER header = (BITMAPINFOHEADER)Marshal.PtrToStructure(_bitmapInfoAddress, typeof(BITMAPINFOHEADER));

                   PixelFormat fmt;
                   switch (header.biBitCount)
                   {
                       case 32:
                           fmt = PixelFormat.Format32bppRgb;
                           break;
                       case 24:
                           fmt = PixelFormat.Format24bppRgb;
                           break;
                       case 16:
                           fmt = PixelFormat.Format16bppRgb555;
                           break;
                       default:
                           TouchPal.Error("Invlaid pixel format for " + _sharedMemoryName);
                           return null;
                   }
                   bitmap = new Bitmap(header.biWidth, header.biHeight, ((int)(header.biWidth/8) * header.biBitCount), fmt, _bitmapDataAddress);
               }
               else
               {
                   TouchPal.Debug("Invalid bitmap type identifier (" + identifier + ") for " + _sharedMemoryName);
               }

               return bitmap;
           }

           TouchPal.Debug("No sharmed memory data avaliable for " + _sharedMemoryName);
           return null;
       }

       private void Open()
       {
           Close();
           _fileHandle = OpenFileMapping(SECTION_MAP_READ, false, _sharedMemoryName);
           if (_fileHandle.Equals(IntPtr.Zero))
           {
               int lastError = Marshal.GetLastWin32Error();
               if (lastError != 2)
               {
                   TouchPal.Debug("Error opening file mapping " + lastError);
               }
           }
           _startAddress = MapViewOfFile(_fileHandle, SECTION_MAP_READ, 0, 0, 0);
           _bitmapInfoAddress = new IntPtr(_startAddress.ToInt64() + 4);
           _bitmapDataAddress = new IntPtr(_startAddress.ToInt64() + 44);
       }

       private void Close()
       {
           if (!_fileHandle.Equals(IntPtr.Zero))
           {
               UnmapViewOfFile(_startAddress);
               CloseHandle(_fileHandle);
           }
       }
   }
}

Posted

Many thanks Gadroc!

 

I was expecting something else. Like - reading it out in lua and then sending it via ethernet or something like that. But as I now see your code, I realise that wouldnt make much sense right ;)

I wasnt aware of the fact that you can handle shared memory areas just like files. Or is it a c# feature?

 

Anyway thank you very much again and Ill let you know if I can get this to work without major fps drops.

 

Regards,

 

basedow

Posted
I was expecting something else. Like - reading it out in lua and then sending it via ethernet or something like that. But as I now see your code, I realise that wouldnt make much sense right ;)

I wasnt aware of the fact that you can handle shared memory areas just like files. Or is it a c# feature?

Yea the whole point of shared memory is to not do that from the scripting language. You can render the image straight from the shared memory. The memory mapping features are standard Win32API calls so any language which can call them can do this. You just need to make sure close the shared memory as appropriate, via IDispose or finalizers.

 

Does the shared memory export the whole shkval/abris display or just certain aspects of it or am I misunderstanding its purpose? I dont have touchpal.

The above code was proof of concept type code for TouchPal and was never included in the source tree or official releases. The shared memory does export the entire Shkval texture, but does not export the full ABRIS texture.

Posted (edited)

Ok and now I need to get this as byte[] or other useful java format through JNI ( i guess ) :)...

Edited by =RvE=Yoda

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Posted

What part of the ABRIS is exported Gadroc?

I am still in preparation phase - meaning I am building an application to import the textures, send it via Ethernet and a second application to display it.

So - what exactly do you mean with "the ABRIS is not fully exported"?

 

Regards

 

basedow

Posted
What part of the ABRIS is exported Gadroc?

I am still in preparation phase - meaning I am building an application to import the textures, send it via Ethernet and a second application to display it.

So - what exactly do you mean with "the ABRIS is not fully exported"?

 

Regards

 

basedow

 

The map itself and town labels where in the image last time I tried. It did not include things like the North arrow in the upper left, nor did it include the text below the map.

Posted

Ok - so maybe you have to put that in manually :(

Heading information is one of the easiest I think.

I dont know yet if you can read out the state of the ABRIS menu.

If that works it should not be a problem to put in the information.

 

Regards

 

basedow

  • 4 months later...
Posted (edited)

Sry to be a thread necro, but, I'm going to start ot use this very soon.

I have never used shared memory before in any application.

Am I assuming correctly that DCS sets up a shared memory space when

I first call for example

LoSetSharedTexture("mirrors")

 

Then fill it with some information using lua:

LoUpdateSharedTexture("mirrors")

 

After that I can grab the file handle externally with:

OpenFileMapping(SECTION_MAP_READ, false, [b][color="Red"]"mirrors"[/color][/b]); 

 

When the game closes I use

LoRemoveSharedTexture("mirrors")

 

Do I also need to close it externally?

Edited by =RvE=Yoda

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Posted (edited)

.

Ok I think it must be doing the right thing, but I get seriously low fps

 

export.lua:

function LuaExportStart()
LoSetSharedTexture("mfd1");
end
function LuaExportAfterNextFrame()
LoUpdateSharedTexture("mfd1");
end
function LuaExportStop()
LoRemoveSharedTexture("mfd1");
end

 

LoUpdateSharedTexture Seems to be killing fps. It goes from 60 -> 8 fps if I have that line there. Any advice on what I'm doing wrong?

 

Once I add the second program to read the shared memory, that doesnt affect fps at all.

 

Cpp test:

#include <iostream>
#include <conio.h>
#include <Windows.h>

using std::cout;
using std::endl;

unsigned int SR = 0x0004;

HANDLE hfile;
DWORD written;
RGBTRIPLE *image;
BITMAPINFOHEADER * bihPtr;

int main() {

hfile = OpenFileMapping(SR, false, L"mfd1");
if (hfile!=0) {
	
	cout << endl << "Grabbing data from handle: " << hfile;
	LPVOID memoryPointer = MapViewOfFile(hfile, SR, 0, 0, 0);
	if (memoryPointer!=0) {
	
		cout << endl << "Got memoryPointer: " << memoryPointer;
		bihPtr = (BITMAPINFOHEADER*)(4 +(long)memoryPointer);

		cout << endl << endl << "biSize " << bihPtr->biSize;
		cout << endl << "biWidth " << bihPtr->biWidth; // Will output the width of the bitmap
		cout << endl << "biHeight " << bihPtr->biHeight; // Will output the height of the bitmap
		cout << endl << "biPlanes " << bihPtr->biPlanes;
		cout << endl << "biBitCount " << bihPtr->biBitCount;
		cout << endl << "biCompression " << bihPtr->biCompression;
		cout << endl << "biSizeImage " << bihPtr->biSizeImage;
		cout << endl << "biXPelsPerMeter " << bihPtr->biXPelsPerMeter;
		cout << endl << "biYPelsPerMeter " << bihPtr->biYPelsPerMeter;
		cout << endl << "biClrUsed " << bihPtr->biClrUsed;
		cout << endl << "biClrImportant " << bihPtr->biClrImportant;

	} else {
		cout << endl << "Could not map memory handle to memory address";
	}
	CloseHandle(hfile);
} else {
	cout << endl << "Could not find any shared texture";
}
_getch();
return 0;
}

 

shared%20Texture.PNG

Edited by =RvE=Yoda

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Posted

Yoda, try to set cockpit resolution to the lowest. You need a very good computer otherwise. Copying memory from the video card to system memory is slow.

Posted (edited)
Yoda, try to set cockpit resolution to the lowest. You need a very good computer otherwise. Copying memory from the video card to system memory is slow.

 

I'm running an E8400 and 4GB ram, but it seems that is not enough :(.

I think even with an i7 I could not get more than 16 fps while exporting

the texture at my current resolution.

 

When playing for example Open Falcon I was told it is possible to export

both MFDs at real time/high fps using shared memory, so I had

assumed it was also possible in DCS.

 

I guess for DCS we should use the ingame settings for rendering on

other monitors instead? Maybe there is simply no need to export the

textures through shared memory (I'm using the wrong approach).

Edited by =RvE=Yoda

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Posted

When I tried exporting MFD in OF it did not work very well with high update as the framerate would go down quite a bit

PC specs:

Windows 11 Home | Asus TUF Gaming B850-Plus WiFi | AMD Ryzen 7 9800X3D + LC 360 AIO | MSI RTX 5090 LC 360 AIO | 55" Samsung Odyssey Gen 2 | 64GB PC5-48000 DDR5 | 1TB M2 SSD for OS | 2TB M2 SSD for DCS | NZXT C1000 Gold ATX 3.1 1000W | TM Cougar Throttle, Floor Mounted MongoosT-50 Grip on TM Cougar board, MFG Crosswind, Track IR

Posted

have you tried updating the shared texture less often? Call LoUpdatedSharedTexture("mfd1"); every tenth frame or something, instead of everyframe? You would sacrifice frame rate of the exported image for frame rate of the main simulation. This could possibly cause a stutter in the simulation, but may not be noticeable, and may improve things overall. This is just a theory, I have not tried it myself.

Posted
have you tried updating the shared texture less often? Call LoUpdatedSharedTexture("mfd1"); every tenth frame or something, instead of everyframe? You would sacrifice frame rate of the exported image for frame rate of the main simulation. This could possibly cause a stutter in the simulation, but may not be noticeable, and may improve things overall. This is just a theory, I have not tried it myself.

 

Stutters unfortunately, but thanks for the idea. I strikes me now that we dont need to export the textures.

All we need to do is to use the built in multi monitor capability :P

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

Posted

Exporting a texture from graphics VRAM to main memory is always slow. The entire system is optimised to do it the other way around (it is far more usual for textures are deleted in VRAM rather than copied back, so graphics systems are not optimized to copy back in an efficient manner). Yeah, the multi-monitor capability sounds like the best bet.

 

I wonder whether you can embed the multi-monitor window in an existing window? That way the rendering is controlled by BlackShark, you simply control the position of where it renders and the z-order.

Posted

I wonder whether you can embed the multi-monitor window in an existing window? That way the rendering is controlled by BlackShark, you simply control the position of where it renders and the z-order.

 

yes it is possible, Gadroc has already done it.

It is on top by default and you can set your control buttons around it to not steal focus when pressed.

S = SPARSE(m,n) abbreviates SPARSE([],[],[],m,n,0). This generates the ultimate sparse matrix, an m-by-n all zero matrix. - Matlab help on 'sparse'

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...