1
\$\begingroup\$

I have a following code , and i can not retrive encoded Output from Job.

If I Use JOB : The result is not a valid png file. What I get is a 67,2 MB file which can not be opened with any image editor I tried. When I open it with a text editor, it seems to contain only whitespaces.

else i got normal valid png file saved on my disc .

Can we use this approach for encoding inside Unity ?

public class Loger : MonoBehaviour
{
    [SerializeField]
    public bool isLoging = true;

    [SerializeField]
    private RenderTexture _rt;
    private NativeArray<byte> _data;
    private AsyncGPUReadbackRequest _request;

    public bool useJob; 

    private void Start()
    {
        CreateBuffer(ref _data, ref _rt);
        StartCoroutine(StartEncoding(_rt, isLoging));
    
    }

    System.Collections.IEnumerator StartEncoding(RenderTexture oRTs, bool active)
    {
        int i = 0; 
        while (active)
        {
            _request= AsyncGPUReadback.RequestIntoNativeArray(ref _data, oRTs, 0);
        if(_request.hasError)
            {
                Debug.Log("Error in GPU request "); break; 
            }

            yield return new WaitUntil(() => _request.done);
        
            if(useJob)
            {
                Debug.Log("creating  Job");
                EncodeJob job = new EncodeJob
                {
                    input = new NativeArray<byte>(_data, Allocator.TempJob),
                    output = new NativeArray<byte>(_data.Length, Allocator.TempJob),
                    graphicsFormat = oRTs.graphicsFormat,
                    width = oRTs.width,
                    height = oRTs.height,
                    result = new NativeArray<int>(1, Allocator.TempJob)
                };


                JobHandle jobTask = job.Schedule();
                jobTask.Complete();
                Debug.Log("result from job is " + " " + job.result[0]);
                var data = job.output;
                Debug.Log("created PNG file ");
                string pathName = "Logs/" + "FLCW" + "/" + i++ + "JOB" + ".png";
                System.IO.File.WriteAllBytes(pathName, data.ToArray());
                yield return new WaitUntil(() => _request.done);
            }

            else if(!useJob)
            {
                var fileData =ImageConversion.EncodeNativeArrayToPNG(_data, oRTs.graphicsFormat, (uint)oRTs.width, (uint)oRTs.height);
                Debug.Log("created PNG file ");
                string pathName = "Logs/" + "FLCW" + "/" + i++ + "MAIN" +".png" ;
                System.IO.File.WriteAllBytes(pathName, fileData.ToArray());
                yield return new WaitUntil(() => _request.done);
            }
          
            yield return new WaitUntil(() => _request.done);
        }
    }

    void CreateBuffer(ref NativeArray<byte> buffer, ref RenderTexture oRTS)
    {
        buffer = new NativeArray<byte>(oRTS.height * oRTS.width * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    }

    private void OnApplicationQuit()
    {
        _data.Dispose();
    }


    struct EncodeJob : IJob
    {
        public NativeArray<byte> input;
        public NativeArray<byte>  output;
        public GraphicsFormat graphicsFormat;
        public NativeArray<int> result;
        public int width;
        public int height;      
            public void Execute()
        {        
            output = ImageConversion.EncodeNativeArrayToPNG(input,graphicsFormat,(uint)width,(uint)height);
            result[0] = width + height;
        }
       
    }


}
\$\endgroup\$
11
  • 1
    \$\begingroup\$ In what way exactly is the returned PNG data "invalid"? Is there any data at all? Is it a valid PNG file? If not what about it is broken specifically? And does the code for PNG encoding work when you run it regularly and not as part of a job? \$\endgroup\$
    – Philipp
    May 11, 2022 at 10:54
  • \$\begingroup\$ @Philipp file i have is not PNG valid , i can not open it after saving as a png . EncodeJob i have it there on the end of the script i have attached . \$\endgroup\$ May 11, 2022 at 10:57
  • 1
    \$\begingroup\$ Did you look at the file in a hex editor to confirm if it has a PNG header? \$\endgroup\$
    – Philipp
    May 11, 2022 at 10:57
  • \$\begingroup\$ @Philipp no .if i open with Notpad its just blanc , empty file ....huge empty white space file . No PNG header as in other .png files i have . \$\endgroup\$ May 11, 2022 at 11:06
  • \$\begingroup\$ When you open a valid PNG file in a text editor, then it should begin with the line ‰PNG followed by binary gibberish. What's the file size? Is it a 0 byte file or does it contain lots of whitespaces? \$\endgroup\$
    – Philipp
    May 11, 2022 at 11:53

1 Answer 1

3
\$\begingroup\$

After testing I found a few problems.

  1. The png format does not save the color information of each pixel. It is a compressed image format. The length of the btyes written to the file is obviously uncompressed.

  2. According to 1, you can't know the size of the png before starting the job. The size allocated for the output can only be used as the buffer size.

  3. Assignment to member variables during job execution is invalid, that's why you use NativeArray to hold the resulting value. So the assignment to output is also invalid:

    public void Execute()
    {        
        output = ...
    }
    

Fix:

  1. Use NativeArray to pass out the length of the resulting array.
  2. Use the length value to slice the output and save it to a file.

Code:

EncodeJob job = new EncodeJob
{
    ...
    result = new NativeArray<int>(2, Allocator.TempJob)
};

JobHandle jobTask = job.Schedule();
jobTask.Complete();

Debug.Log("result from job is " + " " + job.result[0]);
var data = new byte[job.result[1]];
NativeArray<byte>.Copy(job.output, data, job.result[1]);
Debug.Log("created PNG file ");
string pathName = "Logs/" + "FLCW" + "/" + i++ + "JOB" + ".png";
System.IO.File.WriteAllBytes(pathName, data);

And:

public void Execute()
{
    var o = ImageConversion.EncodeArrayToPNG(input.ToArray(), graphicsFormat,
    (uint)width, (uint)height);
    NativeArray<byte>.Copy(o, output, o.Length);
    result[0] = width + height;
    result[1] = o.Length;
}
\$\endgroup\$
4
  • \$\begingroup\$ yes , thank you . its a correct answer .I was going around it but was not sure how to make it thats way i have that result of int inside our code at first place :) \$\endgroup\$ May 11, 2022 at 14:24
  • \$\begingroup\$ When you've verified an answer is correct, you should click the checkmark icon in the top-left to mark the answer as Accepted. \$\endgroup\$
    – DMGregory
    May 11, 2022 at 14:29
  • \$\begingroup\$ When I copy from the return value of EncodeArrayToPNG, I get a "InvalidOperationException: The UNKNOWN_OBJECT_TYPE has been declared as [WriteOnly] in the job, but you are reading from it.". Anyone else getting this? \$\endgroup\$ Mar 17 at 11:24
  • \$\begingroup\$ @AndersEmil Welcome to GDSE. You may post a new question on this. \$\endgroup\$
    – Mangata
    Mar 18 at 13:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .