github.com/racerxdl/gonx@v0.0.0-20210103083128-c5afc43bcbd2/services/display/surface.go (about) 1 package display 2 3 import ( 4 "fmt" 5 "github.com/racerxdl/gonx/nx/graphics" 6 "github.com/racerxdl/gonx/nx/memory" 7 "github.com/racerxdl/gonx/nx/nxerrors" 8 "github.com/racerxdl/gonx/nx/nxtypes" 9 "github.com/racerxdl/gonx/services/am" 10 "github.com/racerxdl/gonx/services/gpu" 11 "github.com/racerxdl/gonx/services/nv" 12 "github.com/racerxdl/gonx/services/vi" 13 "github.com/racerxdl/gonx/svc" 14 "image" 15 "unsafe" 16 ) 17 18 // SurfaceState Keeps track of the internal state of a \ref surface_t 19 type SurfaceState int 20 21 const ( 22 SURFACE_STATE_INVALID SurfaceState = iota 23 SURFACE_STATE_DEQUEUED SurfaceState = iota 24 SURFACE_STATE_QUEUED SurfaceState = iota 25 ) 26 27 type Surface struct { 28 LayerId uint64 29 IGBP vi.IGBP 30 IGBPIsConnected bool 31 State SurfaceState 32 HasRequested []bool 33 CurrentSlot uint32 34 35 GpuBuffer *gpu.Buffer 36 GpuBufferMemory []byte 37 GpuBufferMemoryAlloc uintptr 38 GraphicBuffers []GraphicBuffer 39 CurrentFence Fence 40 GRBuff *nv.GraphicBuffer 41 42 status int 43 } 44 45 func (s *Surface) Connect() (int, error) { 46 if s.IGBPIsConnected { 47 return s.status, nil 48 } 49 50 status, _, err := IGBPConnect(s.IGBP, NativeWindowAPICPU, false) 51 s.status = status 52 if err != nil { 53 return status, err 54 } 55 s.IGBPIsConnected = true 56 57 return status, err 58 } 59 60 func (s *Surface) Disconnect() { 61 if s.IGBPIsConnected { 62 _, _ = IGBPDisconnect(s.IGBP, 2, DisconnectAllLocal) 63 } 64 s.IGBPIsConnected = false 65 } 66 67 func (s *Surface) Destroy() { 68 if s.State == SURFACE_STATE_INVALID { 69 return 70 } 71 72 _, _ = s.DequeueBuffer() 73 74 s.Disconnect() 75 _ = vi.AdjustRefCount(s.IGBP.IgbpBinder.Handle, -1, 1) 76 _ = vi.CloseLayer(s.LayerId) 77 78 aruid, err := am.IwcGetAppletResourceUserId() 79 if err != nil { 80 return 81 } 82 if aruid == 0 { 83 _ = vi.DestroyManagedLayer(s.LayerId) 84 } 85 s.State = SURFACE_STATE_INVALID 86 87 svc.SetMemoryAttribute(uintptr(unsafe.Pointer(&s.GpuBufferMemory[0])), uintptr(0x3c0000*len(s.GraphicBuffers)), 0, 0) 88 _, _, _ = s.GpuBuffer.Destroy() 89 s.GpuBufferMemory = nil 90 } 91 92 func (s *Surface) CloseLayer() error { 93 if displayInitializations < 1 { 94 return nxerrors.DisplayNotInitialized 95 } 96 97 s.Destroy() 98 _ = vi.AdjustRefCount(s.IGBP.IgbpBinder.Handle, -1, 1) 99 _ = vi.CloseLayer(s.LayerId) 100 _ = vi.DestroyManagedLayer(s.LayerId) 101 102 return nil 103 } 104 105 func (s *Surface) DequeueBuffer() ([]byte, error) { 106 if s.State != SURFACE_STATE_QUEUED { 107 return nil, nxerrors.SurfaceInvalidState 108 } 109 110 bf := s.GraphicBuffers[s.CurrentSlot] 111 112 status, slot, fence, _, err := IGBPDequeueBuffer(s.IGBP, bf.Width, bf.Height, bf.Format, bf.Usage, false) 113 if err != nil { 114 return nil, err 115 } 116 117 s.CurrentSlot = slot 118 s.CurrentFence = fence 119 120 if status != 0 { 121 return nil, nxerrors.SurfaceBufferDequeueFailed 122 } 123 if !s.HasRequested[s.CurrentSlot] { 124 _, _, err = IGBPRequestBuffer(s.IGBP, s.CurrentSlot) 125 if err != nil { 126 return nil, err 127 } 128 s.HasRequested[s.CurrentSlot] = true 129 } 130 131 imageSlice := s.GpuBufferMemory[(s.CurrentSlot * s.GRBuff.TotalSize):] 132 s.State = SURFACE_STATE_DEQUEUED 133 134 return imageSlice, nil 135 } 136 137 func (s *Surface) QueueBuffer() error { 138 if s.State != SURFACE_STATE_DEQUEUED { 139 return nxerrors.SurfaceInvalidState 140 } 141 142 qbi := &QueueBufferInput{ 143 Size: uint32(unsafe.Sizeof(QueueBufferInput{}) - 8), 144 Unknown: [2]uint32{0, 1}, 145 Fence: Fence{ 146 IsValid: 1, 147 Sync: [4]gpu.Fence{ 148 {SyncptId: 0xffffffff}, 149 {SyncptId: 0xffffffff}, 150 {SyncptId: 0xffffffff}, 151 {SyncptId: 0xffffffff}, 152 }, 153 }, 154 } 155 156 _, status, err := IGBPQueueBuffer(s.IGBP, int(s.CurrentSlot), qbi) 157 if err != nil { 158 return err 159 } 160 161 if status != 0 { 162 return nxerrors.SurfaceBufferQueueFailed 163 } 164 165 s.State = SURFACE_STATE_QUEUED 166 167 return nil 168 } 169 170 func SurfaceCreate(layerId uint64, igbp vi.IGBP) (surface *Surface, status int, err error) { 171 if debugDisplay { 172 fmt.Printf("Display::SurfaceCreate(%d, %d)\n", layerId, igbp.IgbpBinder.Handle) 173 } 174 175 defer func() { 176 if err != nil && surface != nil { 177 surface.Disconnect() 178 } 179 }() 180 181 format := graphics.PixelFormatRgba8888 182 width := uint32(1280) 183 height := uint32(720) 184 numFbs := 2 185 186 nvColorFmt := nv.ColorFormatTable[format-graphics.PixelFormatRgba8888] 187 bytesPerPixel := uint32(nvColorFmt>>3) & 0x1f 188 blockHeightLog2 := uint32(4) // According to TRM this is the optimal value (SIXTEEN_GOBS) 189 blockHeight := uint32(8 * (1 << blockHeightLog2)) 190 191 grBuf := nv.GraphicBuffer{} 192 grBuf.Header.NumInts = int32(uint64(unsafe.Sizeof(grBuf)-unsafe.Sizeof(nxtypes.NativeHandle{})) / 4) 193 grBuf.Unk0 = -1 194 grBuf.Magic = 0xDAFFCAFF 195 grBuf.PID = 42 196 grBuf.Usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE 197 grBuf.Format = uint32(format) 198 grBuf.ExtFormat = grBuf.Format 199 grBuf.NumPlanes = 1 200 201 grBuf.Planes[0].Width = width 202 grBuf.Planes[0].Height = height 203 grBuf.Planes[0].ColorFormat = nvColorFmt 204 grBuf.Planes[0].Layout = nv.LayoutBlockLinear 205 grBuf.Planes[0].Kind = nv.KindPitch 206 grBuf.Planes[0].BlockHeightLog2 = blockHeightLog2 207 208 widthAlignedBytes := (width*bytesPerPixel + 63) & ^uint32(63) // GOBs are 64 bytes wide 209 widthAligned := widthAlignedBytes / bytesPerPixel 210 heightAligned := (height + blockHeight - 1) & ^(blockHeight - 1) 211 fbSize := widthAlignedBytes * heightAligned 212 bufferSize := int(((uint32(numFbs) * fbSize) + 0xFFF) & ^uint32(0xFFF)) 213 214 surface = &Surface{ 215 LayerId: layerId, 216 IGBP: igbp, 217 State: SURFACE_STATE_INVALID, 218 CurrentSlot: 0, 219 GraphicBuffers: []GraphicBuffer{}, 220 GRBuff: &grBuf, 221 } 222 223 surface.GpuBufferMemory = memory.AllocPages(bufferSize, bufferSize) 224 if surface.GpuBufferMemory == nil { 225 return nil, status, nxerrors.OutOfMemory 226 } 227 228 if debugDisplay { 229 fmt.Printf("Allocated %d bytes\n", len(surface.GpuBufferMemory)) 230 } 231 232 surface.GpuBuffer, err = gpu.CreateBuffer(unsafe.Pointer(&surface.GpuBufferMemory[0]), uintptr(bufferSize), 0, 0x1000, grBuf.Planes[0].Kind) 233 if err != nil { 234 return nil, status, err 235 } 236 237 nvmapId, err := surface.GpuBuffer.GetID() 238 if err != nil { 239 _, _, _ = surface.GpuBuffer.Destroy() 240 return nil, status, err 241 } 242 243 grBuf.NVMapID = int32(nvmapId) 244 grBuf.Stride = widthAligned 245 grBuf.TotalSize = fbSize 246 grBuf.Planes[0].Pitch = widthAlignedBytes 247 grBuf.Planes[0].Size = uint64(fbSize) 248 249 for i := 0; i < numFbs; i++ { 250 grBuf.Planes[0].Offset = uint32(i) * fbSize 251 surface.GraphicBuffers = append(surface.GraphicBuffers, GraphicBuffer{ 252 GRBuff: &grBuf, 253 Width: grBuf.Planes[0].Width, 254 Height: grBuf.Planes[0].Height, 255 Stride: grBuf.Stride, 256 Format: format, 257 Length: fbSize, 258 Usage: grBuf.Usage, 259 GPUBuffer: surface.GpuBuffer, 260 }) 261 surface.HasRequested = append(surface.HasRequested, false) 262 if debugDisplay { 263 fmt.Printf("Pre-allocating buffer %d\n", i) 264 } 265 err = IGBPSetPreallocatedBuffer(surface.IGBP, i, &surface.GraphicBuffers[i]) 266 if err != nil { 267 return nil, 0, err 268 } 269 } 270 271 surface.State = SURFACE_STATE_QUEUED 272 return surface, status, nil 273 } 274 275 func (s *Surface) refreshFrame(f *Frame) error { 276 data, err := s.DequeueBuffer() 277 if err != nil { 278 return err 279 } 280 slot := s.CurrentSlot 281 282 f.surfaceBuff = data 283 f.bounds = image.Rect(0, 0, int(s.GraphicBuffers[slot].Width), int(s.GraphicBuffers[slot].Height)) 284 285 b := f.bounds.Size() 286 l := b.X * b.Y * 4 // uint32 per pixel 287 288 if len(f.buff) != l { 289 if debugDisplay { 290 fmt.Printf("Allocating buffer of %d bytes\n", l) 291 } 292 f.buff = make([]byte, l) 293 } 294 295 return nil 296 } 297 298 // GetFrame returns a frame to be draw on screen 299 func (s *Surface) GetFrame() (*Frame, error) { 300 f := &Frame{ 301 surface: s, 302 buff: nil, 303 surfaceBuff: nil, 304 } 305 306 err := s.refreshFrame(f) 307 if err != nil { 308 return nil, err 309 } 310 311 return f, nil 312 }