unit emit_MIMG;

{$mode objfpc}{$H+}

interface

uses
  sysutils,
  spirv,
  si_ci_vi_merged_enum,
  ps4_shader,
  ps4_pssl,
  srNode,
  srType,
  srReg,
  srLayout,
  srOp,
  srUniform,
  emit_fetch;

type
 TsrImageMods=Set Of (imMinLod,imGrad,imLod,imBiasLod,imZeroLod,imDref,imOffset,imGather);

 TImgSampleParam=object
  roffset:DWORD;
  mods   :TsrImageMods;
  img_op :Integer;

  coord,pcf,bias,lod,min_lod,offset:TsrRegNode;
 end;

 TExtDistrib=record
  dst  :TsrRegNode;
  dtype:TsrDataType;
  id   :Integer;
 end;

 AExtDistrib=array[0..3] of TExtDistrib;

 TEmit_MIMG=class(TEmitFetch)
  procedure emit_MIMG;
  procedure DistribDmask            (DMASK:Byte;dst:TsrRegNode;info:PsrImageInfo);
  procedure DistribDmaskExt         (DMASK:Byte;const ext:AExtDistrib;info:PsrImageInfo);
  function  GatherDmask             (info:PsrImageInfo;relax:Boolean):TsrRegNode;
  Function  GatherCoord_f           (var offset:DWORD;info:PsrImageInfo):TsrRegNode;
  Function  GatherCoord_u           (var offset:DWORD;info:PsrImageInfo):TsrRegNode;
  Function  Gather_value            (var offset:DWORD;rtype:TsrDataType):TsrRegNode;
  Function  Gather_packed_offset    (var offset:DWORD;dim:Byte):TsrRegNode;
  procedure Gather_sample_param     (var p:TImgSampleParam;info:PsrImageInfo);
  procedure add_sample_op           (var p:TImgSampleParam;node:TSpirvOp);
  procedure emit_image_sample       (Tgrp,Sgrp:TsrNode;info:PsrImageInfo);
  procedure emit_image_sample_gather(Tgrp,Sgrp:TsrNode;info:PsrImageInfo);
  procedure emit_image_load         (Tgrp:TsrNode;info:PsrImageInfo);
  procedure emit_image_store        (Tgrp:TsrNode;info:PsrImageInfo);
  procedure emit_image_get_resinfo  (Tgrp:TsrNode;info:PsrImageInfo);
  procedure emit_image_get_lod      (Tgrp,Sgrp:TsrNode;info:PsrImageInfo);
 end;

implementation

function GetImageElemCount(PT:PTSharpResource4):Byte;
begin
 Result:=0;
 if (PT=nil) then Exit;
 Case PT^.dfmt of

  IMG_DATA_FORMAT_8                :Result:=1;
  IMG_DATA_FORMAT_ETC2_R           :Result:=1;
  IMG_DATA_FORMAT_BC4              :Result:=1;
  IMG_DATA_FORMAT_1                :Result:=1;
  IMG_DATA_FORMAT_32_AS_8          :Result:=1;
  IMG_DATA_FORMAT_16               :Result:=1;
  IMG_DATA_FORMAT_32               :Result:=1;

  IMG_DATA_FORMAT_8_8              :Result:=2;
  IMG_DATA_FORMAT_16_16            :Result:=2;
  IMG_DATA_FORMAT_ETC2_RG          :Result:=2;
  IMG_DATA_FORMAT_BC5              :Result:=2;
  IMG_DATA_FORMAT_4_4              :Result:=2;
  IMG_DATA_FORMAT_32_AS_8_8        :Result:=2;
  IMG_DATA_FORMAT_32_32            :Result:=2;
  IMG_DATA_FORMAT_8_24             :Result:=2;
  IMG_DATA_FORMAT_24_8             :Result:=2;
  IMG_DATA_FORMAT_X24_8_32         :Result:=2;

  IMG_DATA_FORMAT_10_11_11         :Result:=3;
  IMG_DATA_FORMAT_11_11_10         :Result:=3;
  IMG_DATA_FORMAT_5_6_5            :Result:=3;
  IMG_DATA_FORMAT_ETC2_RGB         :Result:=3;
  IMG_DATA_FORMAT_GB_GR            :Result:=3;
  IMG_DATA_FORMAT_BG_RG            :Result:=3;
  IMG_DATA_FORMAT_BC1              :Result:=3;
  IMG_DATA_FORMAT_BC6              :Result:=3;
  IMG_DATA_FORMAT_6_5_5            :Result:=3;
  IMG_DATA_FORMAT_32_32_32         :Result:=3;

  IMG_DATA_FORMAT_10_10_10_2       :Result:=4;
  IMG_DATA_FORMAT_2_10_10_10       :Result:=4;
  IMG_DATA_FORMAT_8_8_8_8          :Result:=4;
  IMG_DATA_FORMAT_1_5_5_5          :Result:=4;
  IMG_DATA_FORMAT_5_5_5_1          :Result:=4;
  IMG_DATA_FORMAT_4_4_4_4          :Result:=4;
  IMG_DATA_FORMAT_ETC2_RGBA        :Result:=4;
  IMG_DATA_FORMAT_ETC2_RGBA1       :Result:=4;
  IMG_DATA_FORMAT_5_9_9_9          :Result:=4;
  IMG_DATA_FORMAT_BC2              :Result:=4;
  IMG_DATA_FORMAT_BC3              :Result:=4;
  IMG_DATA_FORMAT_BC7              :Result:=4;
  IMG_DATA_FORMAT_16_16_16_16      :Result:=4;
  IMG_DATA_FORMAT_32_32_32_32      :Result:=4;

  IMG_DATA_FORMAT_FMASK8_S2_F1     :Result:=1;
  IMG_DATA_FORMAT_FMASK8_S4_F1     :Result:=1;
  IMG_DATA_FORMAT_FMASK8_S8_F1     :Result:=1;
  IMG_DATA_FORMAT_FMASK8_S2_F2     :Result:=1;
  IMG_DATA_FORMAT_FMASK8_S4_F2     :Result:=1;
  IMG_DATA_FORMAT_FMASK8_S4_F4     :Result:=1;

  IMG_DATA_FORMAT_FMASK16_S16_F1   :Result:=1;
  IMG_DATA_FORMAT_FMASK16_S8_F2    :Result:=1;

  IMG_DATA_FORMAT_FMASK32_S16_F2   :Result:=1;
  IMG_DATA_FORMAT_FMASK32_S8_F4    :Result:=1;
  IMG_DATA_FORMAT_FMASK32_S8_F8    :Result:=1;

  IMG_DATA_FORMAT_FMASK64_S16_F4   :Result:=1;
  IMG_DATA_FORMAT_FMASK64_S16_F8   :Result:=1;

  IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=4;

  else;
 end;
end;

function GetImageFormat(PT:PTSharpResource4):Byte;
begin
 Result:=ImageFormat.Unknown;
 if (PT=nil) then Exit;
 Case PT^.nfmt of
  IMG_NUM_FORMAT_UNORM,
  IMG_NUM_FORMAT_SRGB:
    begin //R8, Rg8,Rg16, Rgba8,Rgba16,Rgb10A2

     Case PT^.dfmt of

      IMG_DATA_FORMAT_8                :Result:=ImageFormat.R8;
      IMG_DATA_FORMAT_ETC2_R           :Result:=ImageFormat.R8;
      IMG_DATA_FORMAT_BC4              :Result:=ImageFormat.R8;
      IMG_DATA_FORMAT_1                :Result:=ImageFormat.R8;
      IMG_DATA_FORMAT_32_AS_8          :Result:=ImageFormat.R8;

      IMG_DATA_FORMAT_8_8              :Result:=ImageFormat.Rg8;
      IMG_DATA_FORMAT_16_16            :Result:=ImageFormat.Rg16;
      IMG_DATA_FORMAT_ETC2_RG          :Result:=ImageFormat.Rg8;
      IMG_DATA_FORMAT_BC5              :Result:=ImageFormat.Rg8;
      IMG_DATA_FORMAT_4_4              :Result:=ImageFormat.Rg8;
      IMG_DATA_FORMAT_32_AS_8_8        :Result:=ImageFormat.Rg8;

      IMG_DATA_FORMAT_10_11_11         :Result:=ImageFormat.Rgb10A2;
      IMG_DATA_FORMAT_11_11_10         :Result:=ImageFormat.Rgb10A2;
      IMG_DATA_FORMAT_5_6_5            :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_ETC2_RGB         :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_GB_GR            :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_BG_RG            :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_BC1              :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_BC6              :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_6_5_5            :Result:=ImageFormat.Rgba8;

      IMG_DATA_FORMAT_10_10_10_2       :Result:=ImageFormat.Rgb10A2;
      IMG_DATA_FORMAT_2_10_10_10       :Result:=ImageFormat.Rgb10A2;
      IMG_DATA_FORMAT_8_8_8_8          :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_1_5_5_5          :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_5_5_5_1          :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_4_4_4_4          :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_ETC2_RGBA        :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_ETC2_RGBA1       :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_5_9_9_9          :Result:=ImageFormat.Rgba16;
      IMG_DATA_FORMAT_BC2              :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_BC3              :Result:=ImageFormat.Rgba8;
      IMG_DATA_FORMAT_BC7              :Result:=ImageFormat.Rgba8;

      else;
     end;

    end;

  IMG_NUM_FORMAT_SNORM:
    begin //R8Snorm, Rg8Snorm,Rg16Snorm, Rgba8Snorm,Rgba16Snorm

     Case PT^.dfmt of

      IMG_DATA_FORMAT_8                :Result:=ImageFormat.R8Snorm;
      IMG_DATA_FORMAT_ETC2_R           :Result:=ImageFormat.R8Snorm;
      IMG_DATA_FORMAT_BC4              :Result:=ImageFormat.R8Snorm;
      IMG_DATA_FORMAT_1                :Result:=ImageFormat.R8Snorm;
      IMG_DATA_FORMAT_32_AS_8          :Result:=ImageFormat.R8Snorm;

      IMG_DATA_FORMAT_8_8              :Result:=ImageFormat.Rg8Snorm;
      IMG_DATA_FORMAT_16_16            :Result:=ImageFormat.Rg16Snorm;
      IMG_DATA_FORMAT_ETC2_RG          :Result:=ImageFormat.Rg8Snorm;
      IMG_DATA_FORMAT_BC5              :Result:=ImageFormat.Rg8Snorm;
      IMG_DATA_FORMAT_4_4              :Result:=ImageFormat.Rg8Snorm;
      IMG_DATA_FORMAT_32_AS_8_8        :Result:=ImageFormat.Rg8Snorm;

      IMG_DATA_FORMAT_10_11_11         :Result:=ImageFormat.Rgba16Snorm;
      IMG_DATA_FORMAT_11_11_10         :Result:=ImageFormat.Rgba16Snorm;
      IMG_DATA_FORMAT_5_6_5            :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_ETC2_RGB         :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_GB_GR            :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_BG_RG            :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_BC1              :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_BC6              :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_6_5_5            :Result:=ImageFormat.Rgba8Snorm;

      IMG_DATA_FORMAT_10_10_10_2       :Result:=ImageFormat.Rgba16Snorm;
      IMG_DATA_FORMAT_2_10_10_10       :Result:=ImageFormat.Rgba16Snorm;
      IMG_DATA_FORMAT_8_8_8_8          :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_1_5_5_5          :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_5_5_5_1          :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_4_4_4_4          :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_ETC2_RGBA        :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_ETC2_RGBA1       :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_5_9_9_9          :Result:=ImageFormat.Rgba16Snorm;
      IMG_DATA_FORMAT_BC2              :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_BC3              :Result:=ImageFormat.Rgba8Snorm;
      IMG_DATA_FORMAT_BC7              :Result:=ImageFormat.Rgba8Snorm;

      else;
     end;

    end;

  IMG_NUM_FORMAT_UINT:
    begin //R8ui,R16ui,R32ui, Rg8ui,Rg16ui,Rg32ui, Rgba8ui,Rgba16ui,Rgba32ui,Rgb10a2ui

     Case PT^.dfmt of

      IMG_DATA_FORMAT_8                :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_16               :Result:=ImageFormat.R16ui;
      IMG_DATA_FORMAT_32               :Result:=ImageFormat.R32ui;
      IMG_DATA_FORMAT_ETC2_R           :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_BC4              :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_1                :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_32_AS_8          :Result:=ImageFormat.R8ui;

      IMG_DATA_FORMAT_8_8              :Result:=ImageFormat.Rg8ui;
      IMG_DATA_FORMAT_16_16            :Result:=ImageFormat.Rg16ui;
      IMG_DATA_FORMAT_32_32            :Result:=ImageFormat.Rg32ui;
      IMG_DATA_FORMAT_8_24             :Result:=ImageFormat.Rg32ui;
      IMG_DATA_FORMAT_24_8             :Result:=ImageFormat.Rg32ui;
      IMG_DATA_FORMAT_X24_8_32         :Result:=ImageFormat.Rg32ui;
      IMG_DATA_FORMAT_ETC2_RG          :Result:=ImageFormat.Rg8ui;
      IMG_DATA_FORMAT_BC5              :Result:=ImageFormat.Rg8ui;
      IMG_DATA_FORMAT_4_4              :Result:=ImageFormat.Rg8ui;
      IMG_DATA_FORMAT_32_AS_8_8        :Result:=ImageFormat.Rg8ui;

      IMG_DATA_FORMAT_10_11_11         :Result:=ImageFormat.Rgb10a2ui;
      IMG_DATA_FORMAT_11_11_10         :Result:=ImageFormat.Rgb10a2ui;
      IMG_DATA_FORMAT_32_32_32         :Result:=ImageFormat.Rgba32ui;
      IMG_DATA_FORMAT_5_6_5            :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_ETC2_RGB         :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_GB_GR            :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_BG_RG            :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_BC1              :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_BC6              :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_6_5_5            :Result:=ImageFormat.Rgba8ui;

      IMG_DATA_FORMAT_10_10_10_2       :Result:=ImageFormat.Rgb10a2ui;
      IMG_DATA_FORMAT_2_10_10_10       :Result:=ImageFormat.Rgb10a2ui;
      IMG_DATA_FORMAT_8_8_8_8          :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_16_16_16_16      :Result:=ImageFormat.Rgba16ui;
      IMG_DATA_FORMAT_32_32_32_32      :Result:=ImageFormat.Rgba32ui;
      IMG_DATA_FORMAT_1_5_5_5          :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_5_5_5_1          :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_4_4_4_4          :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_ETC2_RGBA        :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_ETC2_RGBA1       :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_5_9_9_9          :Result:=ImageFormat.Rgba16ui;
      IMG_DATA_FORMAT_BC2              :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_BC3              :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_BC7              :Result:=ImageFormat.Rgba8ui;
      IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=ImageFormat.Rgba32ui;

      IMG_DATA_FORMAT_FMASK8_S2_F1     :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_FMASK8_S4_F1     :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_FMASK8_S8_F1     :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_FMASK8_S2_F2     :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_FMASK8_S4_F2     :Result:=ImageFormat.R8ui;
      IMG_DATA_FORMAT_FMASK8_S4_F4     :Result:=ImageFormat.R8ui;

      IMG_DATA_FORMAT_FMASK16_S16_F1   :Result:=ImageFormat.R16ui;
      IMG_DATA_FORMAT_FMASK16_S8_F2    :Result:=ImageFormat.R16ui;

      IMG_DATA_FORMAT_FMASK32_S16_F2   :Result:=ImageFormat.R32ui;
      IMG_DATA_FORMAT_FMASK32_S8_F4    :Result:=ImageFormat.R32ui;
      IMG_DATA_FORMAT_FMASK32_S8_F8    :Result:=ImageFormat.R32ui;

      IMG_DATA_FORMAT_FMASK64_S16_F4   :Result:=ImageFormat.R64ui;
      IMG_DATA_FORMAT_FMASK64_S16_F8   :Result:=ImageFormat.R64ui;

      else;
     end;

    end;

  IMG_NUM_FORMAT_SINT:
    begin //R8i,R16i,R32i, Rg8i,Rg16i,Rg32i, Rgba8i,Rgba16i,Rgba32i

     Case PT^.dfmt of

      IMG_DATA_FORMAT_8                :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_16               :Result:=ImageFormat.R16i;
      IMG_DATA_FORMAT_32               :Result:=ImageFormat.R32i;
      IMG_DATA_FORMAT_ETC2_R           :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_BC4              :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_1                :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_32_AS_8          :Result:=ImageFormat.R8i;

      IMG_DATA_FORMAT_8_8              :Result:=ImageFormat.Rg8i;
      IMG_DATA_FORMAT_16_16            :Result:=ImageFormat.Rg16i;
      IMG_DATA_FORMAT_32_32            :Result:=ImageFormat.Rg32i;
      IMG_DATA_FORMAT_8_24             :Result:=ImageFormat.Rg32i;
      IMG_DATA_FORMAT_24_8             :Result:=ImageFormat.Rg32i;
      IMG_DATA_FORMAT_X24_8_32         :Result:=ImageFormat.Rg32i;
      IMG_DATA_FORMAT_ETC2_RG          :Result:=ImageFormat.Rg8i;
      IMG_DATA_FORMAT_BC5              :Result:=ImageFormat.Rg8i;
      IMG_DATA_FORMAT_4_4              :Result:=ImageFormat.Rg8i;
      IMG_DATA_FORMAT_32_AS_8_8        :Result:=ImageFormat.Rg8i;

      IMG_DATA_FORMAT_10_11_11         :Result:=ImageFormat.Rgba16i;
      IMG_DATA_FORMAT_11_11_10         :Result:=ImageFormat.Rgba16i;
      IMG_DATA_FORMAT_32_32_32         :Result:=ImageFormat.Rgba32i;
      IMG_DATA_FORMAT_5_6_5            :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_ETC2_RGB         :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_GB_GR            :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_BG_RG            :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_BC1              :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_BC6              :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_6_5_5            :Result:=ImageFormat.Rgba8i;

      IMG_DATA_FORMAT_10_10_10_2       :Result:=ImageFormat.Rgba16i;
      IMG_DATA_FORMAT_2_10_10_10       :Result:=ImageFormat.Rgba16i;
      IMG_DATA_FORMAT_8_8_8_8          :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_16_16_16_16      :Result:=ImageFormat.Rgba16i;
      IMG_DATA_FORMAT_32_32_32_32      :Result:=ImageFormat.Rgba32i;
      IMG_DATA_FORMAT_1_5_5_5          :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_5_5_5_1          :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_4_4_4_4          :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_ETC2_RGBA        :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_ETC2_RGBA1       :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_5_9_9_9          :Result:=ImageFormat.Rgba16i;
      IMG_DATA_FORMAT_BC2              :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_BC3              :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_BC7              :Result:=ImageFormat.Rgba8i;
      IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=ImageFormat.Rgba32i;

      IMG_DATA_FORMAT_FMASK8_S2_F1     :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_FMASK8_S4_F1     :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_FMASK8_S8_F1     :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_FMASK8_S2_F2     :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_FMASK8_S4_F2     :Result:=ImageFormat.R8i;
      IMG_DATA_FORMAT_FMASK8_S4_F4     :Result:=ImageFormat.R8i;

      IMG_DATA_FORMAT_FMASK16_S16_F1   :Result:=ImageFormat.R16i;
      IMG_DATA_FORMAT_FMASK16_S8_F2    :Result:=ImageFormat.R16i;

      IMG_DATA_FORMAT_FMASK32_S16_F2   :Result:=ImageFormat.R32i;
      IMG_DATA_FORMAT_FMASK32_S8_F4    :Result:=ImageFormat.R32i;
      IMG_DATA_FORMAT_FMASK32_S8_F8    :Result:=ImageFormat.R32i;

      IMG_DATA_FORMAT_FMASK64_S16_F4   :Result:=ImageFormat.R64i;
      IMG_DATA_FORMAT_FMASK64_S16_F8   :Result:=ImageFormat.R64i;

      else;
     end;

    end;

  IMG_NUM_FORMAT_USCALED,
  IMG_NUM_FORMAT_SSCALED,
  IMG_NUM_FORMAT_FLOAT:
    begin //R16f,R32f, Rg16f,Rg32f, R11fG11fB10f, Rgba16f,Rgba32f

     Case PT^.dfmt of

      IMG_DATA_FORMAT_16               :Result:=ImageFormat.R16f;
      IMG_DATA_FORMAT_32               :Result:=ImageFormat.R32f;
      IMG_DATA_FORMAT_ETC2_R           :Result:=ImageFormat.R16f;
      IMG_DATA_FORMAT_BC4              :Result:=ImageFormat.R16f;

      IMG_DATA_FORMAT_16_16            :Result:=ImageFormat.Rg16f;
      IMG_DATA_FORMAT_32_32            :Result:=ImageFormat.Rg32f;
      IMG_DATA_FORMAT_8_24             :Result:=ImageFormat.Rg32f;
      IMG_DATA_FORMAT_24_8             :Result:=ImageFormat.Rg32f;
      IMG_DATA_FORMAT_X24_8_32         :Result:=ImageFormat.Rg32f;
      IMG_DATA_FORMAT_ETC2_RG          :Result:=ImageFormat.Rg16f;
      IMG_DATA_FORMAT_BC5              :Result:=ImageFormat.Rg16f;

      IMG_DATA_FORMAT_10_11_11         :Result:=ImageFormat.R11fG11fB10f;
      IMG_DATA_FORMAT_11_11_10         :Result:=ImageFormat.R11fG11fB10f;
      IMG_DATA_FORMAT_32_32_32         :Result:=ImageFormat.Rgba32f;
      IMG_DATA_FORMAT_ETC2_RGB         :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_BC1              :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_BC6              :Result:=ImageFormat.Rgba16f;

      IMG_DATA_FORMAT_10_10_10_2       :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_2_10_10_10       :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_16_16_16_16      :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_32_32_32_32      :Result:=ImageFormat.Rgba32f;
      IMG_DATA_FORMAT_ETC2_RGBA        :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_ETC2_RGBA1       :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_BC2              :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_BC3              :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_BC7              :Result:=ImageFormat.Rgba16f;
      IMG_DATA_FORMAT_32_AS_32_32_32_32:Result:=ImageFormat.Rgba32f;

      else;
     end;

    end;

  else;
 end;
end;

function GetDimType(PT:PTSharpResource4):Byte;
begin
 Result:=0;
 if (PT=nil) then Exit;
 Case PT^._type of
  SQ_RSRC_IMG_1D,
  SQ_RSRC_IMG_1D_ARRAY     :Result:=Dim.Dim1D;
  SQ_RSRC_IMG_2D,
  SQ_RSRC_IMG_2D_ARRAY,
  SQ_RSRC_IMG_2D_MSAA,
  SQ_RSRC_IMG_2D_MSAA_ARRAY:Result:=Dim.Dim2D;
  SQ_RSRC_IMG_3D           :Result:=Dim.Dim3D;
  SQ_RSRC_IMG_CUBE         :Result:=Dim.Cube;
  else;
 end;
end;

function GetElemType(PT:PTSharpResource4):TsrDataType;
begin
 Result:=dtFloat32;
 if (PT=nil) then Exit;
 Case PT^.nfmt of
  IMG_NUM_FORMAT_UINT:Result:=dtUint32;
  IMG_NUM_FORMAT_SINT:Result:=dtInt32;
  else;
 end;
end;

function GetDimCount(b:Byte):Byte;
begin
 Result:=1;
 Case b of
  Dim.Dim2D:Result:=2;
  Dim.Dim3D:Result:=3;
  Dim.Cube :Result:=3;
  else;
 end;
end;

function GetImageInfo(PT:PTSharpResource4):TsrImageInfo;
begin
 //print_tsharp8(Pointer(PT));

 Result:=Default(TsrImageInfo);

 Result.dtype        :=GetElemType(PT);
 Result.count        :=GetImageElemCount(PT);

 Result.tinfo.Dim    :=GetDimType(PT);
 Result.tinfo.Depth  :=2;
 Result.tinfo.Arrayed:=GetArrayedType(PT);
 Result.tinfo.MS     :=GetMsType(PT);
 Result.tinfo.Format :=GetImageFormat(PT);

 //convert Cube to array of 2D slices
 if (Result.tinfo.Dim=Dim.Cube) then
 begin
  Result.tinfo.Dim    :=Dim.Dim2D;
  Result.Cube         :=True;
  Result.tinfo.Arrayed:=1;
 end;
end;

function GetImageMods(OP:Byte):TsrImageMods;
begin
 Case OP of
  IMAGE_SAMPLE_CL       :Result:=[imMinLod];
  IMAGE_SAMPLE_D        :Result:=[imGrad];
  IMAGE_SAMPLE_D_CL     :Result:=[imGrad,imMinLod];
  IMAGE_SAMPLE_L        :Result:=[imLod];
  IMAGE_SAMPLE_B        :Result:=[imBiasLod];
  IMAGE_SAMPLE_B_CL     :Result:=[imBiasLod,imMinLod];
  IMAGE_SAMPLE_LZ       :Result:=[imZeroLod];
  IMAGE_SAMPLE_C        :Result:=[imDref];
  IMAGE_SAMPLE_C_CL     :Result:=[imDref,imMinLod];
  IMAGE_SAMPLE_C_D      :Result:=[imDref,imGrad];
  IMAGE_SAMPLE_C_D_CL   :Result:=[imDref,imGrad,imMinLod];
  IMAGE_SAMPLE_C_L      :Result:=[imDref,imLod];
  IMAGE_SAMPLE_C_B      :Result:=[imDref,imBiasLod];
  IMAGE_SAMPLE_C_B_CL   :Result:=[imDref,imBiasLod,imMinLod];
  IMAGE_SAMPLE_C_LZ     :Result:=[imDref,imZeroLod];
  IMAGE_SAMPLE_O        :Result:=[imOffset];
  IMAGE_SAMPLE_CL_O     :Result:=[imMinLod,imOffset];
  IMAGE_SAMPLE_D_O      :Result:=[imGrad,imOffset];
  IMAGE_SAMPLE_D_CL_O   :Result:=[imGrad,imMinLod,imOffset];
  IMAGE_SAMPLE_L_O      :Result:=[imLod,imOffset];
  IMAGE_SAMPLE_B_O      :Result:=[imBiasLod,imOffset];
  IMAGE_SAMPLE_B_CL_O   :Result:=[imBiasLod,imMinLod,imOffset];
  IMAGE_SAMPLE_LZ_O     :Result:=[imZeroLod,imOffset];
  IMAGE_SAMPLE_C_O      :Result:=[imDref,imOffset];
  IMAGE_SAMPLE_C_CL_O   :Result:=[imDref,imMinLod,imOffset];
  IMAGE_SAMPLE_C_D_O    :Result:=[imDref,imGrad,imOffset];
  IMAGE_SAMPLE_C_D_CL_O :Result:=[imDref,imGrad,imMinLod,imOffset];
  IMAGE_SAMPLE_C_L_O    :Result:=[imDref,imLod,imOffset];
  IMAGE_SAMPLE_C_B_O    :Result:=[imDref,imBiasLod,imOffset];
  IMAGE_SAMPLE_C_B_CL_O :Result:=[imDref,imBiasLod,imMinLod,imOffset];
  IMAGE_SAMPLE_C_LZ_O   :Result:=[imDref,imZeroLod,imOffset];
  //
  IMAGE_GATHER4_CL      :Result:=[imGather,imMinLod];
  IMAGE_GATHER4_L       :Result:=[imGather,imLod];
  IMAGE_GATHER4_B       :Result:=[imGather,imBiasLod];
  IMAGE_GATHER4_B_CL    :Result:=[imGather,imBiasLod,imMinLod];
  IMAGE_GATHER4_LZ      :Result:=[imGather,imZeroLod];
  IMAGE_GATHER4_C       :Result:=[imGather,imDref];
  IMAGE_GATHER4_C_CL    :Result:=[imGather,imDref,imMinLod];
  IMAGE_GATHER4_C_L     :Result:=[imGather,imDref,imLod];
  IMAGE_GATHER4_C_B     :Result:=[imGather,imDref,imBiasLod];
  IMAGE_GATHER4_C_B_CL  :Result:=[imGather,imDref,imBiasLod,imMinLod];
  IMAGE_GATHER4_C_LZ    :Result:=[imGather,imDref,imZeroLod];
  IMAGE_GATHER4_O       :Result:=[imGather,imOffset];
  IMAGE_GATHER4_CL_O    :Result:=[imGather,imMinLod,imOffset];
  IMAGE_GATHER4_L_O     :Result:=[imGather,imLod,imOffset];
  IMAGE_GATHER4_B_O     :Result:=[imGather,imBiasLod,imOffset];
  IMAGE_GATHER4_B_CL_O  :Result:=[imGather,imBiasLod,imMinLod,imOffset];
  IMAGE_GATHER4_LZ_O    :Result:=[imGather,imZeroLod,imOffset];
  IMAGE_GATHER4_C_O     :Result:=[imGather,imDref,imOffset];
  IMAGE_GATHER4_C_CL_O  :Result:=[imGather,imDref,imMinLod,imOffset];
  IMAGE_GATHER4_C_L_O   :Result:=[imGather,imDref,imLod,imOffset];
  IMAGE_GATHER4_C_B_O   :Result:=[imGather,imDref,imBiasLod,imOffset];
  IMAGE_GATHER4_C_B_CL_O:Result:=[imGather,imDref,imBiasLod,imMinLod,imOffset];
  IMAGE_GATHER4_C_LZ_O  :Result:=[imGather,imDref,imZeroLod,imOffset];
  //
  IMAGE_SAMPLE_CD       :Result:=[imGrad];
  IMAGE_SAMPLE_CD_CL    :Result:=[imGrad,imMinLod];
  IMAGE_SAMPLE_C_CD     :Result:=[imDref,imGrad];
  IMAGE_SAMPLE_C_CD_CL  :Result:=[imDref,imGrad,imMinLod];
  IMAGE_SAMPLE_CD_O     :Result:=[imGrad,imOffset];
  IMAGE_SAMPLE_CD_CL_O  :Result:=[imGrad,imMinLod,imOffset];
  IMAGE_SAMPLE_C_CD_O   :Result:=[imDref,imGrad,imOffset];
  IMAGE_SAMPLE_C_CD_CL_O:Result:=[imDref,imGrad,imMinLod,imOffset];
  else
    Result:=[];
 end;
end;

function GetImgOpStr(i:Integer):RawByteString;

 procedure t(o:Integer;const v:RawByteString); inline;
 begin
  if ((o and i)<>0) then
  begin
   if (Result<>'') then
   begin
    Result:=Result+'|'+v;
   end else
   begin
    Result:=v;
   end;
  end;
 end;

begin
 Result:='';
 t(ImageOperands.Bias        ,'Bias');
 t(ImageOperands.Lod         ,'Lod');
 t(ImageOperands.Grad        ,'Grad');
 t(ImageOperands.ConstOffset ,'ConstOffset');
 t(ImageOperands.Offset      ,'Offset');
 t(ImageOperands.Sample      ,'Sample');
 t(ImageOperands.MinLod      ,'MinLod');
end;

procedure TEmit_MIMG.DistribDmask(DMASK:Byte;dst:TsrRegNode;info:PsrImageInfo); //result
var
 i:Integer;
 ext:AExtDistrib;
begin
 ext:=Default(AExtDistrib);
 For i:=0 to 3 do
 begin
  ext[i].dst  :=dst;
  ext[i].dtype:=dst.dtype.Child;
  ext[i].id   :=i;
 end;

 DistribDmaskExt(DMASK,ext,info);
end;

procedure TEmit_MIMG.DistribDmaskExt(DMASK:Byte;const ext:AExtDistrib;info:PsrImageInfo); //result
var
 pSlot:PsrRegSlot;
 i,d,max:Byte;
begin

 d:=0;
 For i:=0 to 3 do
 begin
  if DMASK.TestBit(i) then
  begin
   pSlot:=get_vdst8(FSPI.MIMG.VDATA+d);
   Inc(d);
   Assert(pSlot<>nil);

   if (ext[i].dst=nil) then
   begin

    SetConst_i(pSlot,ext[i].dtype,0);

   end else
   if (ext[i].dst.dtype.isScalar) then
   begin

    if (i=0) then
    begin
     MakeCopy(pSlot,ext[i].dst);
    end else
    begin
     SetConst_i(pSlot,ext[i].dtype,0);
    end;

   end else
   begin
    max:=ext[i].dst.dtype.Count;

    if (i<max) then
    begin
     OpExtract(line,pSlot^.New(ext[i].dtype),ext[i].dst,ext[i].id);
    end else
    begin
     SetConst_i(pSlot,ext[i].dtype,0);
    end;

   end;

  end;
 end;

end;

function TEmit_MIMG.GatherDmask(info:PsrImageInfo;relax:Boolean):TsrRegNode;
var
 src:array[0..3] of TsrRegNode;
 i,d,m:Byte;
begin
 Assert(info^.count<>0);

 d:=0;
 m:=info^.count;
 For i:=0 to m-1 do
 begin
  if Byte(FSPI.MIMG.DMASK).TestBit(i) then
  begin
   src[i]:=fetch_vsrc8(FSPI.MIMG.VDATA+d,info^.dtype);
   if not relax then
   begin
    PrepTypeNode(src[i],info^.dtype,False);
   end;
   Inc(d);
  end else
  begin
   src[i]:=NewImm_i(info^.dtype,0);
  end;
 end;

 if (m=1) then
 begin
  Result:=src[0];
 end else
 begin
  Result:=OpMakeVec(line,info^.dtype.AsVector(m),@src);
 end;
end;

Function TEmit_MIMG.GatherCoord_f(var offset:DWORD;info:PsrImageInfo):TsrRegNode; //src
var
 src:array[0..3] of TsrRegNode;

 i,count:Byte;
begin
 Result:=nil;

 if (info^.Cube) then
 begin
  //(u[, v] … [, array layer])

  if (FSPI.MIMG.DA<>0) then //slice
  begin
   count:=4;
   //x,y,slice,(face_id+slice*8)

   src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtFloat32); //x
   src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtFloat32); //y
   src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+3,dtFloat32); //(face_id+slice*8) -> array layer

  end else
  begin
   count:=3;
   //x,y,(face_id)

   src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtFloat32); //x
   src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtFloat32); //y
   src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+2,dtFloat32); //face_id -> array layer

  end;

  Result:=OpMakeVec(line,TsrDataType(dtFloat32).AsVector(3),@src);

 end else
 begin

  count:=GetDimCount(info^.tinfo.Dim);
  if (FSPI.MIMG.DA<>0) then Inc(count); //slice

  For i:=0 to count-1 do
  begin
   src[i]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+i,dtFloat32);
  end;

  if (info^.tinfo.Arrayed<>0) and //is array
     (FSPI.MIMG.DA=0) then        //not slice
  begin
   i:=count;
   Inc(count);

   src[i]:=NewImm_s(dtFloat32,0);
  end;

  if (count=1) then
  begin
   Result:=src[0];
  end else
  begin
   Result:=OpMakeVec(line,TsrDataType(dtFloat32).AsVector(count),@src);
  end;

 end;

 offset:=offset+count;
end;

Function TEmit_MIMG.GatherCoord_u(var offset:DWORD;info:PsrImageInfo):TsrRegNode; //src
var
 src:array[0..3] of TsrRegNode;
 i,count:Byte;
begin
 Result:=nil;

 if (info^.Cube) then
 begin
  //(u[, v] … [, array layer])

  if (FSPI.MIMG.DA<>0) then //slice
  begin
   count:=4;
   //x,y,slice,(face_id+slice*8)

   src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtInt32); //x
   src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtInt32); //y
   src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+3,dtInt32); //(face_id+slice*8) -> array layer

  end else
  begin
   count:=3;
   //x,y,(face_id)

   src[0]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+0,dtInt32); //x
   src[1]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+1,dtInt32); //y
   src[2]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+2,dtInt32); //face_id -> array layer

  end;

  Result:=OpMakeVec(line,TsrDataType(dtInt32).AsVector(3),@src);

 end else
 begin

  count:=GetDimCount(info^.tinfo.Dim);
  if (FSPI.MIMG.DA<>0) then Inc(count); //slice

  For i:=0 to count-1 do
  begin
   src[i]:=fetch_vsrc8(FSPI.MIMG.VADDR+offset+i,dtInt32);
  end;

  if (info^.tinfo.Arrayed<>0) and //is array
     (FSPI.MIMG.DA=0) then        //not slice
  begin
   i:=count;
   Inc(count);

   src[i]:=NewImm_i(dtInt32,0);
  end;

  if (count=1) then
  begin
   Result:=src[0];
  end else
  begin
   Result:=OpMakeVec(line,TsrDataType(dtInt32).AsVector(count),@src);
  end;

 end;

 offset:=offset+count;
end;

Function TEmit_MIMG.Gather_value(var offset:DWORD;rtype:TsrDataType):TsrRegNode;
begin
 Result:=fetch_vsrc8(FSPI.MIMG.VADDR+offset,rtype);
 Inc(offset);
end;

Function TEmit_MIMG.Gather_packed_offset(var offset:DWORD;dim:Byte):TsrRegNode;
var
 src:TsrRegNode;
begin
 Result:=nil;

 src:=fetch_vsrc8(FSPI.MIMG.VADDR+offset,dtUint32);
 Inc(offset);

 Case dim of
  1:Result:=OpPackOfs(line,dtInt32,dim,src);
  2:Result:=OpPackOfs(line,dtVec2i,dim,src);
  3:Result:=OpPackOfs(line,dtVec3i,dim,src);
  else
   Assert(False);
 end;

end;

procedure TEmit_MIMG.Gather_sample_param(var p:TImgSampleParam;info:PsrImageInfo);
begin
 p.roffset:=0;
 p.mods:=GetImageMods(FSPI.MIMG.OP);
 p.img_op:=0;

 //gather
 if (imOffset in p.mods) then
 begin
  p.offset:=Gather_packed_offset(p.roffset,GetDimCount(info^.tinfo.Dim));

  if (imGather in p.mods) then
  begin
   p.img_op:=p.img_op or ImageOperands.Offset;
   AddCapability(Capability.ImageGatherExtended); //-> ImageOperands.Offset
  end else
  begin
   p.img_op:=p.img_op or ImageOperands.ConstOffset;
  end;

 end;

 if (imBiasLod in p.mods) then
 begin
  p.bias:=Gather_value(p.roffset,dtFloat32);
  p.img_op:=p.img_op or ImageOperands.Bias;
 end;

 if (imDref in p.mods) then
 begin
  p.pcf:=Gather_value(p.roffset,dtFloat32);
 end;

 if (imGrad in p.mods) then
 begin
  //TODO: imGrad
  Assert(false,'TODO: imGrad');
 end;

 p.coord:=GatherCoord_f(p.roffset,info);

 if (imLod in p.mods) then
 begin
  p.lod:=Gather_value(p.roffset,dtFloat32);
  p.img_op:=p.img_op or ImageOperands.Lod;
 end else
 if (imZeroLod in p.mods) then
 begin
  p.lod:=NewImm_s(dtFloat32,0);
  p.img_op:=p.img_op or ImageOperands.Lod;
 end;

 if (imMinLod in p.mods) then
 begin
  p.min_lod:=Gather_value(p.roffset,dtFloat32);
  p.img_op:=p.img_op or ImageOperands.MinLod;
 end;
 //gather
end;

procedure TEmit_MIMG.add_sample_op(var p:TImgSampleParam;node:TSpirvOp);
begin
 //ImageOperands
 if (p.img_op<>0) then
 begin
  node.AddLiteral(p.img_op,GetImgOpStr(p.img_op));

  if ((p.img_op and ImageOperands.Bias)<>0) then
  begin
   node.AddParam(p.bias);
  end;

  if ((p.img_op and ImageOperands.Lod)<>0) then
  begin
   node.AddParam(p.lod);
  end;

  if ((p.img_op and ImageOperands.Grad)<>0) then
  begin
   //TODO: imGrad
   Assert(false,'TODO: imGrad');
  end;

  if ((p.img_op and ImageOperands.ConstOffset)<>0) or
     ((p.img_op and ImageOperands.Offset)<>0) then
  begin
   node.AddParam(p.offset);
  end;

  if ((p.img_op and ImageOperands.MinLod)<>0) then
  begin
   node.AddParam(p.min_lod);
   AddCapability(Capability.MinLod);
  end;

 end;
 //ImageOperands
end;

procedure TEmit_MIMG.emit_image_sample(Tgrp,Sgrp:TsrNode;info:PsrImageInfo);
var
 dst,cmb:TsrRegNode;

 param:TImgSampleParam;

 node:TSpirvOp;
begin

 cmb:=OpSampledImage(line,Tgrp,Sgrp,info^.dtype,info^.tinfo);

 //gather
 param:=Default(TImgSampleParam);
 Gather_sample_param(param,info);
 //gather

 if (imDref in param.mods) then
 begin
  dst:=NewReg(info^.dtype);
 end else
 begin
  dst:=NewReg(info^.dtype.AsVector(4));
 end;

 //OpImage
 if (imDref in param.mods) then
 begin
  if (FExecutionModel=ExecutionModel.Fragment) and
     ((param.img_op and ImageOperands.Lod)=0) then
  begin
   //scalar
   node:=OpImageSampleDrefImplicitLod(line,cmb,dst,param.coord,param.pcf);
  end else
  begin
   //scalar
   node:=OpImageSampleDrefExplicitLod(line,cmb,dst,param.coord,param.pcf);
  end;
 end else
 begin
  if (FExecutionModel=ExecutionModel.Fragment) and
     ((param.img_op and ImageOperands.Lod)=0) then
  begin
   //vector
   node:=OpImageSampleImplicitLod(line,cmb,dst,param.coord);
  end else
  begin
   //vector
   node:=OpImageSampleExplicitLod(line,cmb,dst,param.coord);
  end;
 end;
 //OpImage

 //ImageOperands
 add_sample_op(param,node);
 //ImageOperands

 DistribDmask(FSPI.MIMG.DMASK,dst,info);
end;

procedure TEmit_MIMG.emit_image_sample_gather(Tgrp,Sgrp:TsrNode;info:PsrImageInfo);
var
 dst,cmb:TsrRegNode;

 param:TImgSampleParam;
 id:Byte;

 node:TSpirvOp;
begin

 cmb:=OpSampledImage(line,Tgrp,Sgrp,info^.dtype,info^.tinfo);

 dst:=NewReg(info^.dtype.AsVector(4));

 //gather
 param:=Default(TImgSampleParam);
 Gather_sample_param(param,info);
 //gather

 id:=BsrByte(FSPI.MIMG.DMASK);
 //OpImage
 if (imDref in param.mods) then
 begin
  Assert(id=0,'gather pcf with non red component');
  //vector
  node:=OpImageDrefGather(line,cmb,dst,param.coord,param.pcf);
 end else
 begin
  //vector
  node:=OpImageGather(line,cmb,dst,param.coord,id);
 end;
 //OpImage

 //TODO: emulate bias/lod/minlod
 //OpExtension "SPV_AMD_texture_gather_bias_lod"
 //Capability.ImageGatherBiasLodAMD
 //VK_AMD_texture_gather_bias_lod
 begin
  param.img_op:=param.img_op and (not (ImageOperands.Bias or ImageOperands.Lod or ImageOperands.MinLod))
 end;

 //ImageOperands
 add_sample_op(param,node);
 //ImageOperands

 DistribDmask(15,dst,info);
end;

procedure TEmit_MIMG.emit_image_load(Tgrp:TsrNode;info:PsrImageInfo);
var
 dst,coord,lod,smp:TsrRegNode;

 roffset:DWORD;

 node:TSpirvOp;
begin

 dst:=NewReg(info^.dtype.AsVector(4));

 roffset:=0;

 Case FSPI.MIMG.OP of
  IMAGE_LOAD:
    begin
     coord:=GatherCoord_u(roffset,info);

     //vector
     node:=OpImageFetch(line,Tgrp,dst,coord);

     if (info^.tinfo.MS<>0) then //fragid T# 2D MSAA
     begin
      smp:=Gather_value(roffset,dtUint32);

      node.AddLiteral(ImageOperands.Sample,'Sample');
      node.AddParam(smp);
     end;
    end;
  IMAGE_LOAD_MIP: //All except MSAA
    begin
     coord:=GatherCoord_u(roffset,info);

     //vector
     node:=OpImageFetch(line,Tgrp,dst,coord);

     lod:=Gather_value(roffset,dtUint32);

     node.AddLiteral(ImageOperands.Lod,'Lod');
     node.AddParam(lod);
    end;
  else
    Assert(false,'MIMG?'+IntToStr(FSPI.MIMG.OP));
 end;

 DistribDmask(FSPI.MIMG.DMASK,dst,info);
end;

procedure TEmit_MIMG.emit_image_store(Tgrp:TsrNode;info:PsrImageInfo);
var
 dst,coord,lod,smp:TsrRegNode;

 roffset:DWORD;

 node:TSpirvOp;
begin
 dst:=GatherDmask(info,False);

 roffset:=0;

 Case FSPI.MIMG.OP of
  IMAGE_STORE:
    begin
     coord:=GatherCoord_u(roffset,info);

     //scalar or vector
     node:=OpImageWrite(line,Tgrp,coord,dst);

     if (info^.tinfo.MS<>0) then //fragid T# 2D MSAA
     begin
      smp:=Gather_value(roffset,dtUint32);

      node.AddLiteral(ImageOperands.Sample,'Sample');
      node.AddParam(smp);
     end;
    end;
  IMAGE_STORE_MIP: //All except MSAA
    begin
     coord:=GatherCoord_u(roffset,info);

     lod:=Gather_value(roffset,dtUint32);

     lod:=OpAndTo(lod,15);

     //lod:=OpNonUniform(lod); TODO

     //fetch image by index
     Tgrp:=TsrUniform(Tgrp).FetchArrayChain(line,lod);

     //scalar or vector
     node:=OpImageWrite(line,Tgrp,coord,dst);
    end;
  else
    Assert(false,'MIMG?'+IntToStr(FSPI.MIMG.OP));
 end;

end;

procedure TEmit_MIMG.emit_image_get_resinfo(Tgrp:TsrNode;info:PsrImageInfo);
var
 offset:DWORD;
 dst,lod:TsrRegNode;

 dvec:TsrDataType;
 i,count_dim,count_query:Byte;

 ext:AExtDistrib;
begin
 offset:=0;
 lod:=Gather_value(offset,dtUint32);

 //{width, height, depth, num_mip_levels}

 if (FSPI.MIMG.DMASK and 8)<>0 then
 begin
  Assert(false,'TODO: IMAGE_GET_RESINFO->OpImageQueryLevels');
 end;

 Case info^.tinfo.Dim of
  Dim.Dim2D:count_dim:=2;
  Dim.Cube :count_dim:=2;
  Dim.Dim3D:count_dim:=3;
  else
            count_dim:=1;
 end;

 count_query:=count_dim;
 if (info^.tinfo.Arrayed<>0) then
 begin
  Inc(count_query);
 end;

 //

 dvec:=TsrDataType(dtUint32).AsVector(count_query);

 dst:=NewReg(dvec);

 //(width [, height] [, depth] [, elements])
 OpImageQuerySizeLod(line,Tgrp,dst,lod);

 //fill
 ext:=Default(AExtDistrib);
 For i:=0 to 3 do
 begin
  ext[i].dtype:=dtUint32;
 end;

 //fill except arrayed elements
 For i:=0 to count_dim-1 do
 begin
  ext[i].dst:=dst;
  ext[i].id :=i;
 end;

 DistribDmaskExt(FSPI.MIMG.DMASK,ext,info);
end;

procedure TEmit_MIMG.emit_image_get_lod(Tgrp,Sgrp:TsrNode;info:PsrImageInfo);
var
 dst,cmb:TsrRegNode;

 param:TImgSampleParam;
begin

 cmb:=OpSampledImage(line,Tgrp,Sgrp,info^.dtype,info^.tinfo);

 //DMASK: {lod, lod_unclamped, 0, 0}

 //gather
 param:=Default(TImgSampleParam);
 param.coord:=GatherCoord_f(param.roffset,info);
 //gather

 dst:=NewReg(dtVec2f);

 //{mipmap_level, lod}
 OpImageQueryLod(line,cmb,dst,param.coord);

 DistribDmask(FSPI.MIMG.DMASK,dst,info);

 AddCapability(Capability.ImageQuery);
end;

procedure TEmit_MIMG.emit_MIMG;
var
 src:array[0..7] of PsrRegSlot;

 pLayout_Sgrp:TsrDataLayout;
 pLayout_Tgrp:TsrDataLayout;

 info:TsrImageInfo;

 Sgrp:TsrNode;
 Tgrp:TsrNode;

 PS:PSSharpResource4;
begin
 pLayout_Sgrp:=nil;
 pLayout_Tgrp:=nil;

 Sgrp:=nil;
 Tgrp:=nil;

 Case FSPI.MIMG.OP of
  IMAGE_SAMPLE ..IMAGE_SAMPLE_C_LZ_O,  //sampled
  IMAGE_GATHER4..IMAGE_GATHER4_C_LZ_O, //sampled gather
  IMAGE_GET_LOD:
    begin
     if not get_srsrc(FSPI.MIMG.SSAMP,4,@src) then Assert(false);

     pLayout_Sgrp:=GroupingSharp(src,rtSSharp4);
     Sgrp:=FetchSampler(pLayout_Sgrp);
    end;
  else;
 end;

 Case FSPI.MIMG.R128 of
  0: //256=8 *4*8
    begin
     if not get_srsrc(FSPI.MIMG.SRSRC,8,@src) then Assert(false);
     pLayout_Tgrp:=GroupingSharp(src,rtTSharp8);
    end;
  1: //128=4 *4*8
    begin
     if not get_srsrc(FSPI.MIMG.SRSRC,4,@src) then Assert(false);
     pLayout_Tgrp:=GroupingSharp(src,rtTSharp4);
    end;
 end;

 info:=GetImageInfo(pLayout_Tgrp.GetSharp);

 info.GLC:=(FSPI.MIMG.GLC<>0);

 if (pLayout_Sgrp<>nil) then
 begin
  PS:=pLayout_Sgrp.GetSharp;
  info.degam:=(PS^.force_degamma<>0);
 end;

 if (imDref in GetImageMods(FSPI.MIMG.OP)) then
 begin
  info.tinfo.Depth:=1;
 end;

 Case FSPI.MIMG.OP of
  IMAGE_SAMPLE..IMAGE_SAMPLE_C_LZ_O:  //sampled
    begin
     Assert(FSPI.MIMG.UNRM=0,'FSPI.MIMG.UNRM');

     info.tinfo.Sampled:=1;
     Tgrp:=FetchImage(pLayout_Tgrp,info);

     emit_image_sample(Tgrp,Sgrp,@info);
    end;

  IMAGE_GATHER4..IMAGE_GATHER4_C_LZ_O: //sampled gather
    begin
     Assert(FSPI.MIMG.UNRM=0,'FSPI.MIMG.UNRM');

     info.tinfo.Sampled:=1;
     Tgrp:=FetchImage(pLayout_Tgrp,info);

     emit_image_sample_gather(Tgrp,Sgrp,@info);
    end;

  IMAGE_LOAD..IMAGE_LOAD_MIP_PCK_SGN: //loaded
    begin
     info.tinfo.Sampled:=1;
     Tgrp:=FetchImage(pLayout_Tgrp,info);

     emit_image_load(Tgrp,@info);
    end;

  IMAGE_STORE,
  IMAGE_STORE_PCK: //stored
    begin
     info.tinfo.Sampled:=2;
     Tgrp:=FetchImage(pLayout_Tgrp,info);

     emit_image_store(Tgrp,@info);
    end;

  IMAGE_STORE_MIP,
  IMAGE_STORE_MIP_PCK: //stored mip
    begin
     info.tinfo.Sampled:=2;
     //Tgrp:=FetchImageRuntimeArray(pLayout_Tgrp,info);
     Tgrp:=FetchImageArray(pLayout_Tgrp,info,16);
     TsrUniform(Tgrp).FMipArray:=True;

     emit_image_store(Tgrp,@info);
    end;

  IMAGE_GET_RESINFO: //get info by mip
    begin
     info.tinfo.Sampled:=1;
     Tgrp:=FetchImage(pLayout_Tgrp,info);

     emit_image_get_resinfo(Tgrp,@info);
    end;

  IMAGE_GET_LOD:
    begin
     info.tinfo.Sampled:=1;
     Tgrp:=FetchImage(pLayout_Tgrp,info);

     emit_image_get_lod(Tgrp,Sgrp,@info);
    end;

  else
    Assert(false,'MIMG?'+IntToStr(FSPI.MIMG.OP)+' '+get_str_spi(FSPI));
 end;

 //Writeln('DMASK=',FSPI.MIMG.DMASK);
 //Writeln('VADDR=',FSPI.MIMG.VADDR);
 //Writeln('VDATA=',FSPI.MIMG.VDATA);
 //Writeln('SRSRC=',FSPI.MIMG.SRSRC); //T#
 //Writeln('SSAMP=',FSPI.MIMG.SSAMP); //S#
 //writeln;
end;

end.




