1
0

metal-indexbuffer.swift 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /******************************************************************************
  2. Copyright (C) 2024 by Patrick Heyer <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ******************************************************************************/
  14. import Foundation
  15. import Metal
  16. /// Creates a ``MetalIndexBuffer`` object to share with `libobs` and hold the provided indices
  17. ///
  18. /// - Parameters:
  19. /// - device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
  20. /// - type: Size of each index value (16 bit or 32 bit)
  21. /// - indices: Opaque pointer to index buffer data set up by `libobs`
  22. /// - num: Count of vertices present at the memory address provided by the `indices` argument
  23. /// - flags: Bit field of `libobs` buffer flags
  24. /// - Returns: Opaque pointer to a retained ``MetalIndexBuffer`` instance if valid index type was provided, `nil`
  25. /// otherwise
  26. ///
  27. /// > Note: The ownership of the memory pointed to by `indices` is implicitly transferred to the ``MetalIndexBuffer``
  28. /// instance, but is not managed by Swift.
  29. @_cdecl("device_indexbuffer_create")
  30. public func device_indexbuffer_create(
  31. device: UnsafeRawPointer, type: gs_index_type, indices: UnsafeMutableRawPointer, num: UInt32, flags: UInt32
  32. ) -> OpaquePointer? {
  33. let device: MetalDevice = unretained(device)
  34. guard let indexType = type.mtlType else {
  35. return nil
  36. }
  37. let indexBuffer = MetalIndexBuffer(
  38. device: device,
  39. type: indexType,
  40. data: indices,
  41. count: Int(num),
  42. dynamic: (Int32(flags) & GS_DYNAMIC) != 0
  43. )
  44. return indexBuffer.getRetained()
  45. }
  46. /// Sets up a ``MetalIndexBuffer`` as the index buffer for the current pipeline
  47. /// - Parameters:
  48. /// - device: Opaque pointer to ``MetalDevice`` instance shared with `libobs`
  49. /// - indexbuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  50. ///
  51. /// > Note: The reference count of the ``MetalIndexBuffer`` instance will not be increased by this call.
  52. ///
  53. /// > Important: If a `nil` pointer is provided as the index buffer, the index buffer will be _unset_.
  54. @_cdecl("device_load_indexbuffer")
  55. public func device_load_indexbuffer(device: UnsafeRawPointer, indexbuffer: UnsafeRawPointer?) {
  56. let device: MetalDevice = unretained(device)
  57. if let indexbuffer {
  58. device.renderState.indexBuffer = unretained(indexbuffer)
  59. } else {
  60. device.renderState.indexBuffer = nil
  61. }
  62. }
  63. /// Requests the deinitialization of a shared ``MetalIndexBuffer`` instance
  64. /// - Parameter indexBuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  65. ///
  66. /// The deinitialization is handled automatically by Swift after the ownership of the instance has been transferred
  67. /// into the function and becomes the last strong reference to it. After the function leaves its scope, the object will
  68. /// be deinitialized and deallocated automatically.
  69. ///
  70. /// > Note: The index buffer data memory is implicitly owned by the ``MetalIndexBuffer`` instance and will be manually
  71. /// cleaned up and deallocated by the instance's `deinit` method.
  72. @_cdecl("gs_indexbuffer_destroy")
  73. public func gs_indexbuffer_destroy(indexBuffer: UnsafeRawPointer) {
  74. let _ = retained(indexBuffer) as MetalIndexBuffer
  75. }
  76. /// Requests the index buffer's current data to be transferred into GPU memory
  77. /// - Parameter indexBuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  78. ///
  79. /// This function will call `gs_indexbuffer_flush_direct` with `nil` data pointer.
  80. @_cdecl("gs_indexbuffer_flush")
  81. public func gs_indexbuffer_flush(indexBuffer: UnsafeRawPointer) {
  82. gs_indexbuffer_flush_direct(indexBuffer: indexBuffer, data: nil)
  83. }
  84. /// Requests the index buffer to be updated with the provided data and then transferred into GPU memory
  85. /// - Parameters:
  86. /// - indexBuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  87. /// - data: Opaque pointer to index buffer data set up by `libobs`
  88. ///
  89. /// This function is called to ensure that the index buffer data that is contained in the memory pointed at by the
  90. /// `data` argument is uploaded into GPU memory. If a `nil` pointer is provided instead, the data provided to the
  91. /// instance during creation will be used instead.
  92. @_cdecl("gs_indexbuffer_flush_direct")
  93. public func gs_indexbuffer_flush_direct(indexBuffer: UnsafeRawPointer, data: UnsafeMutableRawPointer?) {
  94. let indexBuffer: MetalIndexBuffer = unretained(indexBuffer)
  95. indexBuffer.setupBuffers(data)
  96. }
  97. /// Returns an opaque pointer to the index buffer data associated with the ``MetalIndexBuffer`` instance
  98. /// - Parameter indexBuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  99. /// - Returns: Opaque pointer to index buffer data in memory
  100. ///
  101. /// The returned opaque pointer represents the unchanged memory address that was provided for the creation of the index
  102. /// buffer object.
  103. ///
  104. /// > Warning: There is only limited memory safety associated with this pointer. It is implicitly owned and its
  105. /// lifetime is managed by the ``MetalIndexBuffer`` instance, but it was originally created by `libobs`.
  106. @_cdecl("gs_indexbuffer_get_data")
  107. public func gs_indexbuffer_get_data(indexBuffer: UnsafeRawPointer) -> UnsafeMutableRawPointer? {
  108. let indexBuffer: MetalIndexBuffer = unretained(indexBuffer)
  109. return indexBuffer.indexData
  110. }
  111. /// Returns the number of indices associated with the ``MetalIndexBuffer`` instance
  112. /// - Parameter indexBuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  113. /// - Returns: Number of index buffers
  114. ///
  115. /// > Note: This returns the same number that was provided for the creation of the index buffer object.
  116. @_cdecl("gs_indexbuffer_get_num_indices")
  117. public func gs_indexbuffer_get_num_indices(indexBuffer: UnsafeRawPointer) -> UInt32 {
  118. let indexBuffer: MetalIndexBuffer = unretained(indexBuffer)
  119. return UInt32(indexBuffer.count)
  120. }
  121. /// Gets the index buffer type as a `libobs` enum value
  122. /// - Parameter indexBuffer: Opaque pointer to ``MetalIndexBuffer`` instance shared with `libobs`
  123. /// - Returns: Index buffer type as identified by the `gs_index_type` enum
  124. ///
  125. /// > Warning: As the `gs_index_type` enumeration does not provide an "invalid" value (and thus `0` becomes a valied
  126. /// value), this function has no way to communicate an incompatible index buffer type that might be introduced at a
  127. /// later point.
  128. @_cdecl("gs_indexbuffer_get_type")
  129. public func gs_indexbuffer_get_type(indexBuffer: UnsafeRawPointer) -> gs_index_type {
  130. let indexBuffer: MetalIndexBuffer = unretained(indexBuffer)
  131. switch indexBuffer.type {
  132. case .uint16: return GS_UNSIGNED_SHORT
  133. case .uint32: return GS_UNSIGNED_LONG
  134. @unknown default:
  135. assertionFailure("gs_indexbuffer_get_type: Unsupported index buffer type \(indexBuffer.type)")
  136. return GS_UNSIGNED_SHORT
  137. }
  138. }