mirror of
				https://github.com/libsdl-org/SDL.git
				synced 2025-10-26 12:27:44 +00:00 
			
		
		
		
	Enable texture wrapping for SDL_RenderGeometry()
Currently wrapping is based on whether texture coordinates are outside of [0,1], but the code is structured so it's easy to add an API to set it and add additional wrapping modes if we want. Fixes https://github.com/libsdl-org/SDL/issues/9238 Closes https://github.com/libsdl-org/SDL/pull/5369
This commit is contained in:
		| @@ -576,6 +576,7 @@ static SDL_RenderCommand *PrepQueueCmdDraw(SDL_Renderer *renderer, const SDL_Ren | ||||
|             cmd->data.draw.color = *color; | ||||
|             cmd->data.draw.blend = blendMode; | ||||
|             cmd->data.draw.texture = texture; | ||||
|             cmd->data.draw.texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP; | ||||
|         } | ||||
|     } | ||||
|     return cmd; | ||||
| @@ -715,12 +716,14 @@ static int QueueCmdGeometry(SDL_Renderer *renderer, SDL_Texture *texture, | ||||
|                             const float *uv, int uv_stride, | ||||
|                             int num_vertices, | ||||
|                             const void *indices, int num_indices, int size_indices, | ||||
|                             float scale_x, float scale_y) | ||||
|                             float scale_x, float scale_y, SDL_TextureAddressMode texture_address_mode) | ||||
| { | ||||
|     SDL_RenderCommand *cmd; | ||||
|     int retval = -1; | ||||
|     cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_GEOMETRY, texture); | ||||
|     if (cmd) { | ||||
|         cmd->data.draw.texture_address_mode = texture_address_mode; | ||||
|  | ||||
|         retval = renderer->QueueGeometry(renderer, cmd, texture, | ||||
|                                          xy, xy_stride, | ||||
|                                          color, color_stride, uv, uv_stride, | ||||
| @@ -3602,7 +3605,7 @@ int SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count) | ||||
|             retval = QueueCmdGeometry(renderer, NULL, | ||||
|                                       xy, xy_stride, &renderer->color, 0 /* color_stride */, NULL, 0, | ||||
|                                       num_vertices, indices, num_indices, size_indices, | ||||
|                                       1.0f, 1.0f); | ||||
|                                       1.0f, 1.0f, SDL_TEXTURE_ADDRESS_CLAMP); | ||||
|         } | ||||
|  | ||||
|         SDL_small_free(xy, isstack1); | ||||
| @@ -3818,7 +3821,7 @@ int SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FR | ||||
|                                   num_vertices, | ||||
|                                   indices, num_indices, size_indices, | ||||
|                                   renderer->view->scale.x, | ||||
|                                   renderer->view->scale.y); | ||||
|                                   renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP); | ||||
|     } else { | ||||
|  | ||||
|         real_dstrect.x *= renderer->view->scale.x; | ||||
| @@ -3976,7 +3979,7 @@ int SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, | ||||
|                                   num_vertices, | ||||
|                                   indices, num_indices, size_indices, | ||||
|                                   renderer->view->scale.x, | ||||
|                                   renderer->view->scale.y); | ||||
|                                   renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP); | ||||
|     } else { | ||||
|  | ||||
|         retval = QueueCmdCopyEx(renderer, texture, &real_srcrect, &real_dstrect, angle, &real_center, flip, | ||||
| @@ -4340,7 +4343,7 @@ static int SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, | ||||
|                                           xy, xy_stride, color, color_stride, uv, uv_stride, | ||||
|                                           num_vertices, prev, 3, 4, | ||||
|                                           renderer->view->scale.x, | ||||
|                                           renderer->view->scale.y); | ||||
|                                           renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP); | ||||
|                 if (retval < 0) { | ||||
|                     goto end; | ||||
|                 } | ||||
| @@ -4361,7 +4364,7 @@ static int SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, | ||||
|                                   xy, xy_stride, color, color_stride, uv, uv_stride, | ||||
|                                   num_vertices, prev, 3, 4, | ||||
|                                   renderer->view->scale.x, | ||||
|                                   renderer->view->scale.y); | ||||
|                                   renderer->view->scale.y, SDL_TEXTURE_ADDRESS_CLAMP); | ||||
|         if (retval < 0) { | ||||
|             goto end; | ||||
|         } | ||||
| @@ -4386,6 +4389,7 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer, | ||||
| { | ||||
|     int i; | ||||
|     int count = indices ? num_indices : num_vertices; | ||||
|     SDL_TextureAddressMode texture_address_mode; | ||||
|  | ||||
|     CHECK_RENDERER_MAGIC(renderer, -1); | ||||
|  | ||||
| @@ -4440,13 +4444,16 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer, | ||||
|         texture = texture->native; | ||||
|     } | ||||
|  | ||||
|     if (texture) { | ||||
|     texture_address_mode = renderer->texture_address_mode; | ||||
|     if (texture_address_mode == SDL_TEXTURE_ADDRESS_AUTO && texture) { | ||||
|         texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP; | ||||
|         for (i = 0; i < num_vertices; ++i) { | ||||
|             const float *uv_ = (const float *)((const char *)uv + i * uv_stride); | ||||
|             float u = uv_[0]; | ||||
|             float v = uv_[1]; | ||||
|             if (u < 0.0f || v < 0.0f || u > 1.0f || v > 1.0f) { | ||||
|                 return SDL_SetError("Values of 'uv' out of bounds %f %f at %d/%d", u, v, i, num_vertices); | ||||
|                 texture_address_mode = SDL_TEXTURE_ADDRESS_WRAP; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -4473,7 +4480,7 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer, | ||||
|  | ||||
|     /* For the software renderer, try to reinterpret triangles as SDL_Rect */ | ||||
| #if SDL_VIDEO_RENDER_SW | ||||
|     if (renderer->software) { | ||||
|     if (renderer->software && texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) { | ||||
|         return SDL_SW_RenderGeometryRaw(renderer, texture, | ||||
|                                         xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, | ||||
|                                         indices, num_indices, size_indices); | ||||
| @@ -4485,7 +4492,7 @@ int SDL_RenderGeometryRaw(SDL_Renderer *renderer, | ||||
|                               num_vertices, | ||||
|                               indices, num_indices, size_indices, | ||||
|                               renderer->view->scale.x, | ||||
|                               renderer->view->scale.y); | ||||
|                               renderer->view->scale.y, texture_address_mode); | ||||
| } | ||||
|  | ||||
| SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) | ||||
|   | ||||
| @@ -30,6 +30,13 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| typedef enum SDL_TextureAddressMode | ||||
| { | ||||
|     SDL_TEXTURE_ADDRESS_AUTO, | ||||
|     SDL_TEXTURE_ADDRESS_CLAMP, | ||||
|     SDL_TEXTURE_ADDRESS_WRAP, | ||||
| } SDL_TextureAddressMode; | ||||
|  | ||||
| /** | ||||
|  * A rectangle, with the origin at the upper left (double precision). | ||||
|  */ | ||||
| @@ -132,6 +139,7 @@ typedef struct SDL_RenderCommand | ||||
|             SDL_FColor color; | ||||
|             SDL_BlendMode blend; | ||||
|             SDL_Texture *texture; | ||||
|             SDL_TextureAddressMode texture_address_mode; | ||||
|         } draw; | ||||
|         struct | ||||
|         { | ||||
| @@ -262,6 +270,7 @@ struct SDL_Renderer | ||||
|     float color_scale; | ||||
|     SDL_FColor color;        /**< Color for drawing operations values */ | ||||
|     SDL_BlendMode blendMode; /**< The drawing blend mode */ | ||||
|     SDL_TextureAddressMode texture_address_mode; | ||||
|  | ||||
|     SDL_RenderCommand *render_commands; | ||||
|     SDL_RenderCommand *render_commands_tail; | ||||
|   | ||||
| @@ -62,7 +62,8 @@ typedef struct | ||||
|     SDL_bool updateSize; | ||||
|     SDL_bool beginScene; | ||||
|     SDL_bool enableSeparateAlphaBlend; | ||||
|     D3DTEXTUREFILTERTYPE scaleMode[8]; | ||||
|     D3DTEXTUREFILTERTYPE scaleMode[3]; | ||||
|     SDL_TextureAddressMode addressMode[3]; | ||||
|     IDirect3DSurface9 *defaultRenderTarget; | ||||
|     IDirect3DSurface9 *currentRenderTarget; | ||||
|     void *d3dxDLL; | ||||
| @@ -277,6 +278,9 @@ static void D3D_InitRenderState(D3D_RenderData *data) | ||||
|     /* Reset our current scale mode */ | ||||
|     SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode)); | ||||
|  | ||||
|     /* Reset our current address mode */ | ||||
|     SDL_zeroa(data->addressMode); | ||||
|  | ||||
|     /* Start the render with beginScene */ | ||||
|     data->beginScene = SDL_TRUE; | ||||
| } | ||||
| @@ -927,19 +931,32 @@ static int BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWO | ||||
| static void UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index) | ||||
| { | ||||
|     if (texturedata->scaleMode != data->scaleMode[index]) { | ||||
|         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, | ||||
|                                          texturedata->scaleMode); | ||||
|         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, | ||||
|                                          texturedata->scaleMode); | ||||
|         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, | ||||
|                                          D3DTADDRESS_CLAMP); | ||||
|         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, | ||||
|                                          D3DTADDRESS_CLAMP); | ||||
|         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, texturedata->scaleMode); | ||||
|         IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, texturedata->scaleMode); | ||||
|         data->scaleMode[index] = texturedata->scaleMode; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, D3D9_Shader *shader, const float **shader_params) | ||||
| static void UpdateTextureAddressMode(D3D_RenderData *data, SDL_TextureAddressMode addressMode, unsigned index) | ||||
| { | ||||
|     if (addressMode != data->addressMode[index]) { | ||||
|         switch (addressMode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); | ||||
|             IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); | ||||
|             IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); | ||||
|             break; | ||||
|         default: | ||||
|             break; | ||||
|         } | ||||
|         data->addressMode[index] = addressMode; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, SDL_TextureAddressMode addressMode, D3D9_Shader *shader, const float **shader_params) | ||||
| { | ||||
|     D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; | ||||
|  | ||||
| @@ -948,6 +965,7 @@ static int SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, D3D9_Sh | ||||
|     } | ||||
|  | ||||
|     UpdateTextureScaleMode(data, texturedata, 0); | ||||
|     UpdateTextureAddressMode(data, addressMode, 0); | ||||
|  | ||||
|     *shader = texturedata->shader; | ||||
|     *shader_params = texturedata->shader_params; | ||||
| @@ -959,6 +977,8 @@ static int SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, D3D9_Sh | ||||
|     if (texturedata->yuv) { | ||||
|         UpdateTextureScaleMode(data, texturedata, 1); | ||||
|         UpdateTextureScaleMode(data, texturedata, 2); | ||||
|         UpdateTextureAddressMode(data, addressMode, 1); | ||||
|         UpdateTextureAddressMode(data, addressMode, 2); | ||||
|  | ||||
|         if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) { | ||||
|             return -1; | ||||
| @@ -994,7 +1014,7 @@ static int SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) | ||||
|             IDirect3DDevice9_SetTexture(data->device, 2, NULL); | ||||
|         } | ||||
| #endif | ||||
|         if (texture && SetupTextureState(data, texture, &shader, &shader_params) < 0) { | ||||
|         if (texture && SetupTextureState(data, texture, cmd->data.draw.texture_address_mode, &shader, &shader_params) < 0) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -68,6 +68,16 @@ extern ISwapChainBackgroundPanelNative *WINRT_GlobalSwapChainBackgroundPanelNati | ||||
| /* !!! FIXME: vertex buffer bandwidth could be lower; only use UV coords when | ||||
|    !!! FIXME:  textures are needed. */ | ||||
|  | ||||
| /* Sampler types */ | ||||
| typedef enum | ||||
| { | ||||
|     SDL_D3D11_SAMPLER_NEAREST_CLAMP, | ||||
|     SDL_D3D11_SAMPLER_NEAREST_WRAP, | ||||
|     SDL_D3D11_SAMPLER_LINEAR_CLAMP, | ||||
|     SDL_D3D11_SAMPLER_LINEAR_WRAP, | ||||
|     SDL_NUM_D3D11_SAMPLERS | ||||
| } SDL_D3D11_sampler_type; | ||||
|  | ||||
| /* Vertex shader, common values */ | ||||
| typedef struct | ||||
| { | ||||
| @@ -181,8 +191,7 @@ typedef struct | ||||
|     ID3D11PixelShader *pixelShaders[NUM_SHADERS]; | ||||
|     int blendModesCount; | ||||
|     D3D11_BlendMode *blendModes; | ||||
|     ID3D11SamplerState *nearestPixelSampler; | ||||
|     ID3D11SamplerState *linearSampler; | ||||
|     ID3D11SamplerState *samplers[SDL_NUM_D3D11_SAMPLERS]; | ||||
|     D3D_FEATURE_LEVEL featureLevel; | ||||
|     SDL_bool pixelSizeChanged; | ||||
|  | ||||
| @@ -346,8 +355,9 @@ static void D3D11_ReleaseAll(SDL_Renderer *renderer) | ||||
|         SAFE_RELEASE(data->vertexShaderConstants); | ||||
|         SAFE_RELEASE(data->clippedRasterizer); | ||||
|         SAFE_RELEASE(data->mainRasterizer); | ||||
|         SAFE_RELEASE(data->linearSampler); | ||||
|         SAFE_RELEASE(data->nearestPixelSampler); | ||||
|         for (i = 0; i < SDL_arraysize(data->samplers); ++i) { | ||||
|             SAFE_RELEASE(data->samplers[i]); | ||||
|         } | ||||
|  | ||||
|         if (data->blendModesCount > 0) { | ||||
|             for (i = 0; i < data->blendModesCount; ++i) { | ||||
| @@ -734,31 +744,35 @@ static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) | ||||
|     } | ||||
|  | ||||
|     /* Create samplers to use when drawing textures: */ | ||||
|     static struct  | ||||
|     { | ||||
|         D3D11_FILTER filter; | ||||
|         D3D11_TEXTURE_ADDRESS_MODE address; | ||||
|     } samplerParams[] = { | ||||
|         { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_CLAMP }, | ||||
|         { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_WRAP }, | ||||
|         { D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP }, | ||||
|         { D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_WRAP }, | ||||
|     }; | ||||
|     SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_NUM_D3D11_SAMPLERS); | ||||
|     SDL_zero(samplerDesc); | ||||
|     samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; | ||||
|     samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; | ||||
|     samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; | ||||
|     samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; | ||||
|     samplerDesc.MipLODBias = 0.0f; | ||||
|     samplerDesc.MaxAnisotropy = 1; | ||||
|     samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; | ||||
|     samplerDesc.MinLOD = 0.0f; | ||||
|     samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; | ||||
|     result = ID3D11Device_CreateSamplerState(data->d3dDevice, | ||||
|                                              &samplerDesc, | ||||
|                                              &data->nearestPixelSampler); | ||||
|     if (FAILED(result)) { | ||||
|         WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [nearest-pixel filter]"), result); | ||||
|         goto done; | ||||
|     } | ||||
|  | ||||
|     samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; | ||||
|     result = ID3D11Device_CreateSamplerState(data->d3dDevice, | ||||
|                                              &samplerDesc, | ||||
|                                              &data->linearSampler); | ||||
|     if (FAILED(result)) { | ||||
|         WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [linear filter]"), result); | ||||
|         goto done; | ||||
|     for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { | ||||
|         samplerDesc.Filter = samplerParams[i].filter; | ||||
|         samplerDesc.AddressU = samplerParams[i].address; | ||||
|         samplerDesc.AddressV = samplerParams[i].address; | ||||
|         result = ID3D11Device_CreateSamplerState(data->d3dDevice, | ||||
|                                                  &samplerDesc, | ||||
|                                                  &data->samplers[i]); | ||||
|         if (FAILED(result)) { | ||||
|             WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [nearest-pixel filter]"), result); | ||||
|             goto done; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /* Setup Direct3D rasterizer states */ | ||||
| @@ -2426,10 +2440,28 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c | ||||
|  | ||||
|     switch (textureData->scaleMode) { | ||||
|     case D3D11_FILTER_MIN_MAG_MIP_POINT: | ||||
|         textureSampler = rendererData->nearestPixelSampler; | ||||
|         switch (cmd->data.draw.texture_address_mode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             textureSampler = rendererData->samplers[SDL_D3D11_SAMPLER_NEAREST_CLAMP]; | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             textureSampler = rendererData->samplers[SDL_D3D11_SAMPLER_NEAREST_WRAP]; | ||||
|             break; | ||||
|         default: | ||||
|             return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|         } | ||||
|         break; | ||||
|     case D3D11_FILTER_MIN_MAG_MIP_LINEAR: | ||||
|         textureSampler = rendererData->linearSampler; | ||||
|         switch (cmd->data.draw.texture_address_mode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             textureSampler = rendererData->samplers[SDL_D3D11_SAMPLER_LINEAR_CLAMP]; | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             textureSampler = rendererData->samplers[SDL_D3D11_SAMPLER_LINEAR_WRAP]; | ||||
|             break; | ||||
|         default: | ||||
|             return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode); | ||||
|   | ||||
| @@ -134,6 +134,16 @@ extern "C" { | ||||
| /* !!! FIXME: vertex buffer bandwidth could be lower; only use UV coords when | ||||
|    !!! FIXME:  textures are needed. */ | ||||
|  | ||||
| /* Sampler types */ | ||||
| typedef enum | ||||
| { | ||||
|     SDL_D3D12_SAMPLER_NEAREST_CLAMP, | ||||
|     SDL_D3D12_SAMPLER_NEAREST_WRAP, | ||||
|     SDL_D3D12_SAMPLER_LINEAR_CLAMP, | ||||
|     SDL_D3D12_SAMPLER_LINEAR_WRAP, | ||||
|     SDL_D3D12_NUM_SAMPLERS | ||||
| } SDL_D3D12_sampler_type; | ||||
|  | ||||
| /* Vertex shader, common values */ | ||||
| typedef struct | ||||
| { | ||||
| @@ -294,8 +304,7 @@ typedef struct | ||||
|     D3D12_PipelineState *currentPipelineState; | ||||
|  | ||||
|     D3D12_VertexBuffer vertexBuffers[SDL_D3D12_NUM_VERTEX_BUFFERS]; | ||||
|     D3D12_CPU_DESCRIPTOR_HANDLE nearestPixelSampler; | ||||
|     D3D12_CPU_DESCRIPTOR_HANDLE linearSampler; | ||||
|     D3D12_CPU_DESCRIPTOR_HANDLE samplers[SDL_D3D12_NUM_SAMPLERS]; | ||||
|  | ||||
|     /* Data for staging/allocating textures */ | ||||
|     ID3D12Resource *uploadBuffers[SDL_D3D12_NUM_UPLOAD_BUFFERS]; | ||||
| @@ -1057,7 +1066,7 @@ static HRESULT D3D12_CreateDeviceResources(SDL_Renderer *renderer) | ||||
|     data->srvDescriptorSize = D3D_CALL(d3dDevice, GetDescriptorHandleIncrementSize, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); | ||||
|  | ||||
|     SDL_zero(descriptorHeapDesc); | ||||
|     descriptorHeapDesc.NumDescriptors = 2; | ||||
|     descriptorHeapDesc.NumDescriptors = 4; | ||||
|     descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; | ||||
|     descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; | ||||
|     result = D3D_CALL(data->d3dDevice, CreateDescriptorHeap, | ||||
| @@ -1165,22 +1174,32 @@ static HRESULT D3D12_CreateDeviceResources(SDL_Renderer *renderer) | ||||
|     } | ||||
|  | ||||
|     /* Create samplers to use when drawing textures: */ | ||||
|     static struct | ||||
|     { | ||||
|         D3D12_FILTER filter; | ||||
|         D3D12_TEXTURE_ADDRESS_MODE address; | ||||
|     } samplerParams[] = { | ||||
|         { D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_CLAMP }, | ||||
|         { D3D12_FILTER_MIN_MAG_MIP_POINT, D3D12_TEXTURE_ADDRESS_MODE_WRAP }, | ||||
|         { D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP }, | ||||
|         { D3D12_FILTER_MIN_MAG_MIP_LINEAR, D3D12_TEXTURE_ADDRESS_MODE_WRAP }, | ||||
|     }; | ||||
|     SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_D3D12_NUM_SAMPLERS); | ||||
|     SDL_zero(samplerDesc); | ||||
|     samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; | ||||
|     samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; | ||||
|     samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; | ||||
|     samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; | ||||
|     samplerDesc.MipLODBias = 0.0f; | ||||
|     samplerDesc.MaxAnisotropy = 1; | ||||
|     samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; | ||||
|     samplerDesc.MinLOD = 0.0f; | ||||
|     samplerDesc.MaxLOD = D3D12_FLOAT32_MAX; | ||||
|     D3D_CALL_RET_ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(data->samplerDescriptorHeap, &data->nearestPixelSampler); | ||||
|     D3D_CALL(data->d3dDevice, CreateSampler, &samplerDesc, data->nearestPixelSampler); | ||||
|  | ||||
|     samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; | ||||
|     data->linearSampler.ptr = data->nearestPixelSampler.ptr + data->samplerDescriptorSize; | ||||
|     D3D_CALL(data->d3dDevice, CreateSampler, &samplerDesc, data->linearSampler); | ||||
|     D3D_CALL_RET_ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(data->samplerDescriptorHeap, &data->samplers[0]); | ||||
|     for (i = 0; i < SDL_arraysize(samplerParams); ++i) { | ||||
|         samplerDesc.Filter = samplerParams[i].filter; | ||||
|         samplerDesc.AddressU = samplerParams[i].address; | ||||
|         samplerDesc.AddressV = samplerParams[i].address; | ||||
|         data->samplers[i].ptr = data->samplers[0].ptr + i * data->samplerDescriptorSize; | ||||
|         D3D_CALL(data->d3dDevice, CreateSampler, &samplerDesc, data->samplers[i]); | ||||
|     } | ||||
|  | ||||
|     /* Initialize the pool allocator for SRVs */ | ||||
|     for (i = 0; i < SDL_D3D12_MAX_NUM_TEXTURES; ++i) { | ||||
| @@ -2797,10 +2816,28 @@ static int D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c | ||||
|  | ||||
|     switch (textureData->scaleMode) { | ||||
|     case D3D12_FILTER_MIN_MAG_MIP_POINT: | ||||
|         textureSampler = &rendererData->nearestPixelSampler; | ||||
|         switch (cmd->data.draw.texture_address_mode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             textureSampler = &rendererData->samplers[SDL_D3D12_SAMPLER_NEAREST_CLAMP]; | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             textureSampler = &rendererData->samplers[SDL_D3D12_SAMPLER_NEAREST_WRAP]; | ||||
|             break; | ||||
|         default: | ||||
|             return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|         } | ||||
|         break; | ||||
|     case D3D12_FILTER_MIN_MAG_MIP_LINEAR: | ||||
|         textureSampler = &rendererData->linearSampler; | ||||
|         switch (cmd->data.draw.texture_address_mode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             textureSampler = &rendererData->samplers[SDL_D3D12_SAMPLER_LINEAR_CLAMP]; | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             textureSampler = &rendererData->samplers[SDL_D3D12_SAMPLER_LINEAR_WRAP]; | ||||
|             break; | ||||
|         default: | ||||
|             return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode); | ||||
|   | ||||
| @@ -80,6 +80,16 @@ static const size_t CONSTANTS_OFFSET_DECODE_BT2020_LIMITED = ALIGN_CONSTANTS(16, | ||||
| static const size_t CONSTANTS_OFFSET_DECODE_BT2020_FULL = ALIGN_CONSTANTS(16, CONSTANTS_OFFSET_DECODE_BT2020_LIMITED + sizeof(float) * 4 * 4); | ||||
| static const size_t CONSTANTS_LENGTH = CONSTANTS_OFFSET_DECODE_BT2020_FULL + sizeof(float) * 4 * 4; | ||||
|  | ||||
| /* Sampler types */ | ||||
| typedef enum | ||||
| { | ||||
|     SDL_METAL_SAMPLER_NEAREST_CLAMP, | ||||
|     SDL_METAL_SAMPLER_NEAREST_WRAP, | ||||
|     SDL_METAL_SAMPLER_LINEAR_CLAMP, | ||||
|     SDL_METAL_SAMPLER_LINEAR_WRAP, | ||||
|     SDL_NUM_METAL_SAMPLERS | ||||
| } SDL_METAL_sampler_type; | ||||
|  | ||||
| typedef enum SDL_MetalVertexFunction | ||||
| { | ||||
|     SDL_METAL_VERTEX_SOLID, | ||||
| @@ -130,8 +140,7 @@ typedef struct METAL_ShaderPipelines | ||||
| @property(nonatomic, retain) id<MTLRenderCommandEncoder> mtlcmdencoder; | ||||
| @property(nonatomic, retain) id<MTLLibrary> mtllibrary; | ||||
| @property(nonatomic, retain) id<CAMetalDrawable> mtlbackbuffer; | ||||
| @property(nonatomic, retain) id<MTLSamplerState> mtlsamplernearest; | ||||
| @property(nonatomic, retain) id<MTLSamplerState> mtlsamplerlinear; | ||||
| @property(nonatomic, retain) NSMutableArray<id<MTLSamplerState>> *mtlsamplers; | ||||
| @property(nonatomic, retain) id<MTLBuffer> mtlbufconstants; | ||||
| @property(nonatomic, retain) id<MTLBuffer> mtlbufquadindices; | ||||
| @property(nonatomic, assign) SDL_MetalView mtlview; | ||||
| @@ -148,7 +157,6 @@ typedef struct METAL_ShaderPipelines | ||||
| @interface METAL_TextureData : NSObject | ||||
| @property(nonatomic, retain) id<MTLTexture> mtltexture; | ||||
| @property(nonatomic, retain) id<MTLTexture> mtltextureUv; | ||||
| @property(nonatomic, retain) id<MTLSamplerState> mtlsampler; | ||||
| @property(nonatomic, assign) SDL_MetalFragmentFunction fragmentFunction; | ||||
| #if SDL_HAVE_YUV | ||||
| @property(nonatomic, assign) BOOL yuv; | ||||
| @@ -739,11 +747,6 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL | ||||
|         } | ||||
| #endif /* SDL_HAVE_YUV */ | ||||
|         texturedata = [[METAL_TextureData alloc] init]; | ||||
|         if (texture->scaleMode == SDL_SCALEMODE_NEAREST) { | ||||
|             texturedata.mtlsampler = data.mtlsamplernearest; | ||||
|         } else { | ||||
|             texturedata.mtlsampler = data.mtlsamplerlinear; | ||||
|         } | ||||
|         if (SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_SRGB) { | ||||
|             texturedata.fragmentFunction = SDL_METAL_FRAGMENT_COPY; | ||||
| #if SDL_HAVE_YUV | ||||
| @@ -1094,16 +1097,6 @@ static void METAL_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) | ||||
|  | ||||
| static void METAL_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) | ||||
| { | ||||
|     @autoreleasepool { | ||||
|         METAL_RenderData *data = (__bridge METAL_RenderData *)renderer->internal; | ||||
|         METAL_TextureData *texturedata = (__bridge METAL_TextureData *)texture->internal; | ||||
|  | ||||
|         if (scaleMode == SDL_SCALEMODE_NEAREST) { | ||||
|             texturedata.mtlsampler = data.mtlsamplernearest; | ||||
|         } else { | ||||
|             texturedata.mtlsampler = data.mtlsamplerlinear; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int METAL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) | ||||
| @@ -1503,13 +1496,32 @@ static SDL_bool SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cm | ||||
|     } | ||||
|  | ||||
|     if (texture != statecache->texture) { | ||||
|         METAL_TextureData *oldtexturedata = NULL; | ||||
|         if (statecache->texture) { | ||||
|             oldtexturedata = (__bridge METAL_TextureData *)statecache->texture->internal; | ||||
|         } | ||||
|         if (!oldtexturedata || (texturedata.mtlsampler != oldtexturedata.mtlsampler)) { | ||||
|             [data.mtlcmdencoder setFragmentSamplerState:texturedata.mtlsampler atIndex:0]; | ||||
|         id<MTLSamplerState> mtlsampler; | ||||
|  | ||||
|         if (texture->scaleMode == SDL_SCALEMODE_NEAREST) { | ||||
|             switch (cmd->data.draw.texture_address_mode) { | ||||
|             case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|                 mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_CLAMP]; | ||||
|                 break; | ||||
|             case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|                 mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_NEAREST_WRAP]; | ||||
|                 break; | ||||
|             default: | ||||
|                 return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|             } | ||||
|         } else { | ||||
|             switch (cmd->data.draw.texture_address_mode) { | ||||
|             case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|                 mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_CLAMP]; | ||||
|                 break; | ||||
|             case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|                 mtlsampler = data.mtlsamplers[SDL_METAL_SAMPLER_LINEAR_WRAP]; | ||||
|                 break; | ||||
|             default: | ||||
|                 return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|             } | ||||
|         } | ||||
|         [data.mtlcmdencoder setFragmentSamplerState:mtlsampler atIndex:0]; | ||||
|  | ||||
|         [data.mtlcmdencoder setFragmentTexture:texturedata.mtltexture atIndex:0]; | ||||
| #if SDL_HAVE_YUV | ||||
| @@ -1904,7 +1916,6 @@ static int METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_ | ||||
|         MTLSamplerDescriptor *samplerdesc; | ||||
|         id<MTLCommandQueue> mtlcmdqueue; | ||||
|         id<MTLLibrary> mtllibrary; | ||||
|         id<MTLSamplerState> mtlsamplernearest, mtlsamplerlinear; | ||||
|         id<MTLBuffer> mtlbufconstantstaging, mtlbufquadindicesstaging, mtlbufconstants, mtlbufquadindices; | ||||
|         id<MTLCommandBuffer> cmdbuffer; | ||||
|         id<MTLBlitCommandEncoder> blitcmd; | ||||
| @@ -2066,17 +2077,27 @@ static int METAL_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_ | ||||
|         data.allpipelines = NULL; | ||||
|         ChooseShaderPipelines(data, MTLPixelFormatBGRA8Unorm); | ||||
|  | ||||
|         static struct | ||||
|         { | ||||
|             MTLSamplerMinMagFilter filter; | ||||
|             MTLSamplerAddressMode address; | ||||
|         } samplerParams[] = { | ||||
|             { MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeClampToEdge }, | ||||
|             { MTLSamplerMinMagFilterNearest, MTLSamplerAddressModeRepeat }, | ||||
|             { MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeClampToEdge }, | ||||
|             { MTLSamplerMinMagFilterLinear, MTLSamplerAddressModeRepeat }, | ||||
|         }; | ||||
|         SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_NUM_METAL_SAMPLERS); | ||||
|  | ||||
|         data.mtlsamplers = [[NSMutableArray<id<MTLSamplerState>> alloc] init]; | ||||
|         samplerdesc = [[MTLSamplerDescriptor alloc] init]; | ||||
|  | ||||
|         samplerdesc.minFilter = MTLSamplerMinMagFilterNearest; | ||||
|         samplerdesc.magFilter = MTLSamplerMinMagFilterNearest; | ||||
|         mtlsamplernearest = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc]; | ||||
|         data.mtlsamplernearest = mtlsamplernearest; | ||||
|  | ||||
|         samplerdesc.minFilter = MTLSamplerMinMagFilterLinear; | ||||
|         samplerdesc.magFilter = MTLSamplerMinMagFilterLinear; | ||||
|         mtlsamplerlinear = [data.mtldevice newSamplerStateWithDescriptor:samplerdesc]; | ||||
|         data.mtlsamplerlinear = mtlsamplerlinear; | ||||
|         for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { | ||||
|             samplerdesc.minFilter = samplerParams[i].filter; | ||||
|             samplerdesc.magFilter = samplerParams[i].filter; | ||||
|             samplerdesc.sAddressMode = samplerParams[i].address; | ||||
|             samplerdesc.tAddressMode = samplerParams[i].address; | ||||
|             [data.mtlsamplers addObject:[data.mtldevice newSamplerStateWithDescriptor:samplerdesc]]; | ||||
|         } | ||||
|  | ||||
|         mtlbufconstantstaging = [data.mtldevice newBufferWithLength:CONSTANTS_LENGTH options:MTLResourceStorageModeShared]; | ||||
|  | ||||
|   | ||||
| @@ -541,15 +541,6 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr | ||||
|     renderdata->glBindTexture(textype, data->texture); | ||||
|     renderdata->glTexParameteri(textype, GL_TEXTURE_MIN_FILTER, scaleMode); | ||||
|     renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, scaleMode); | ||||
|     /* According to the spec, CLAMP_TO_EDGE is the default for TEXTURE_RECTANGLE | ||||
|        and setting it causes an INVALID_ENUM error in the latest NVidia drivers. | ||||
|     */ | ||||
|     if (textype != GL_TEXTURE_RECTANGLE_ARB) { | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|     } | ||||
| #ifdef SDL_PLATFORM_MACOS | ||||
| #ifndef GL_TEXTURE_STORAGE_HINT_APPLE | ||||
| #define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC | ||||
| @@ -609,10 +600,6 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr | ||||
|                                     scaleMode); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, | ||||
|                                     scaleMode); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w + 1) / 2, | ||||
|                                  (texture_h + 1) / 2, 0, format, type, NULL); | ||||
|         SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_U_NUMBER, data->utexture); | ||||
| @@ -622,10 +609,6 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr | ||||
|                                     scaleMode); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, | ||||
|                                     scaleMode); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexImage2D(textype, 0, internalFormat, (texture_w + 1) / 2, | ||||
|                                  (texture_h + 1) / 2, 0, format, type, NULL); | ||||
|         SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_V_NUMBER, data->vtexture); | ||||
| @@ -646,10 +629,6 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr | ||||
|                                     scaleMode); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_MAG_FILTER, | ||||
|                                     scaleMode); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_S, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(textype, GL_TEXTURE_WRAP_T, | ||||
|                                     GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexImage2D(textype, 0, GL_LUMINANCE_ALPHA, (texture_w + 1) / 2, | ||||
|                                  (texture_h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); | ||||
|         SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_OPENGL_TEXTURE_UV_NUMBER, data->utexture); | ||||
| @@ -1141,6 +1120,23 @@ static int SetDrawState(GL_RenderData *data, const SDL_RenderCommand *cmd, const | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int SetTextureAddressMode(GL_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode) | ||||
| { | ||||
|     switch (addressMode) { | ||||
|     case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|         break; | ||||
|     case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_REPEAT); | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT); | ||||
|         break; | ||||
|     default: | ||||
|         return SDL_SetError("Unknown texture address mode: %d\n", addressMode); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) | ||||
| { | ||||
|     SDL_Texture *texture = cmd->data.draw.texture; | ||||
| @@ -1157,16 +1153,28 @@ static int SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) | ||||
|             } | ||||
|             data->glBindTexture(textype, texturedata->vtexture); | ||||
|  | ||||
|             if (SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|  | ||||
|             if (data->GL_ARB_multitexture_supported) { | ||||
|                 data->glActiveTextureARB(GL_TEXTURE1_ARB); | ||||
|             } | ||||
|             data->glBindTexture(textype, texturedata->utexture); | ||||
|  | ||||
|             if (SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|         } | ||||
|         if (texturedata->nv12) { | ||||
|             if (data->GL_ARB_multitexture_supported) { | ||||
|                 data->glActiveTextureARB(GL_TEXTURE1_ARB); | ||||
|             } | ||||
|             data->glBindTexture(textype, texturedata->utexture); | ||||
|  | ||||
|             if (SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
|         if (data->GL_ARB_multitexture_supported) { | ||||
| @@ -1174,6 +1182,10 @@ static int SetCopyState(GL_RenderData *data, const SDL_RenderCommand *cmd) | ||||
|         } | ||||
|         data->glBindTexture(textype, texturedata->texture); | ||||
|  | ||||
|         if (SetTextureAddressMode(data, textype, cmd->data.draw.texture_address_mode) < 0) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         data->drawstate.texture = texture; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1030,6 +1030,23 @@ static int SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, co | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int SetTextureAddressMode(GLES2_RenderData *data, GLenum textype, SDL_TextureAddressMode addressMode) | ||||
| { | ||||
|     switch (addressMode) { | ||||
|     case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|         break; | ||||
|     case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_S, GL_REPEAT); | ||||
|         data->glTexParameteri(textype, GL_TEXTURE_WRAP_T, GL_REPEAT); | ||||
|         break; | ||||
|     default: | ||||
|         return SDL_SetError("Unknown texture address mode: %d\n", addressMode); | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, void *vertices) | ||||
| { | ||||
|     GLES2_RenderData *data = (GLES2_RenderData *)renderer->internal; | ||||
| @@ -1162,18 +1179,35 @@ static int SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, vo | ||||
|             data->glActiveTexture(GL_TEXTURE2); | ||||
|             data->glBindTexture(tdata->texture_type, tdata->texture_v); | ||||
|  | ||||
|             if (SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|  | ||||
|             data->glActiveTexture(GL_TEXTURE1); | ||||
|             data->glBindTexture(tdata->texture_type, tdata->texture_u); | ||||
|  | ||||
|             if (SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|  | ||||
|             data->glActiveTexture(GL_TEXTURE0); | ||||
|         } else if (tdata->nv12) { | ||||
|             data->glActiveTexture(GL_TEXTURE1); | ||||
|             data->glBindTexture(tdata->texture_type, tdata->texture_u); | ||||
|  | ||||
|             if (SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|  | ||||
|             data->glActiveTexture(GL_TEXTURE0); | ||||
|         } | ||||
| #endif | ||||
|         data->glBindTexture(tdata->texture_type, tdata->texture); | ||||
|  | ||||
|         if (SetTextureAddressMode(data, tdata->texture_type, cmd->data.draw.texture_address_mode) < 0) { | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         data->drawstate.texture = texture; | ||||
|     } | ||||
|  | ||||
| @@ -1552,8 +1586,6 @@ static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL | ||||
|         renderdata->glBindTexture(data->texture_type, data->texture_v); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL); | ||||
|         SDL_SetNumberProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_OPENGLES2_TEXTURE_V_NUMBER, data->texture_v); | ||||
|  | ||||
| @@ -1570,8 +1602,6 @@ static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL | ||||
|         renderdata->glBindTexture(data->texture_type, data->texture_u); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL); | ||||
|         if (GL_CheckError("glTexImage2D()", renderer) < 0) { | ||||
|             return -1; | ||||
| @@ -1595,8 +1625,6 @@ static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL | ||||
|         renderdata->glBindTexture(data->texture_type, data->texture_u); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|         renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); | ||||
|         if (GL_CheckError("glTexImage2D()", renderer) < 0) { | ||||
|             return -1; | ||||
| @@ -1623,8 +1651,6 @@ static int GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL | ||||
|     renderdata->glBindTexture(data->texture_type, data->texture); | ||||
|     renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MIN_FILTER, scaleMode); | ||||
|     renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode); | ||||
|     renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|     renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|     if (texture->format != SDL_PIXELFORMAT_EXTERNAL_OES) { | ||||
|         renderdata->glTexImage2D(data->texture_type, 0, format, texture->w, texture->h, 0, format, type, NULL); | ||||
|         if (GL_CheckError("glTexImage2D()", renderer) < 0) { | ||||
|   | ||||
| @@ -928,7 +928,8 @@ static int SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, vo | ||||
|                         &(ptr[0].src), &(ptr[1].src), &(ptr[2].src), | ||||
|                         surface, | ||||
|                         &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), | ||||
|                         ptr[0].color, ptr[1].color, ptr[2].color); | ||||
|                         ptr[0].color, ptr[1].color, ptr[2].color, | ||||
|                         cmd->data.draw.texture_address_mode); | ||||
|                 } | ||||
|             } else { | ||||
|                 GeometryFillData *ptr = (GeometryFillData *)verts; | ||||
|   | ||||
| @@ -42,7 +42,7 @@ static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, | ||||
|                                   SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, | ||||
|                                   int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, | ||||
|                                   int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, | ||||
|                                   SDL_Color c0, SDL_Color c1, SDL_Color c2, int is_uniform); | ||||
|                                   SDL_Color c0, SDL_Color c1, SDL_Color c2, SDL_bool is_uniform, SDL_TextureAddressMode texture_address_mode); | ||||
|  | ||||
| #if 0 | ||||
| int SDL_BlitTriangle(SDL_Surface *src, const SDL_Point srcpoints[3], SDL_Surface *dst, const SDL_Point dstpoints[3]) | ||||
| @@ -183,7 +183,17 @@ static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Poin | ||||
| /* Use 64 bits precision to prevent overflow when interpolating color / texture with wide triangles */ | ||||
| #define TRIANGLE_GET_TEXTCOORD                                                          \ | ||||
|     int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \ | ||||
|     int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); | ||||
|     int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \ | ||||
|     if (texture_address_mode == SDL_TEXTURE_ADDRESS_WRAP) {                             \ | ||||
|         srcx %= src_surface->w;                                                         \ | ||||
|         if (srcx < 0) {                                                                 \ | ||||
|             srcx += (src_surface->w - 1);                                               \ | ||||
|         }                                                                               \ | ||||
|         srcy %= src_surface->h;                                                         \ | ||||
|         if (srcy < 0) {                                                                 \ | ||||
|             srcy += (src_surface->h - 1);                                               \ | ||||
|         }                                                                               \ | ||||
|     } | ||||
|  | ||||
| #define TRIANGLE_GET_MAPPED_COLOR                                                      \ | ||||
|     Uint8 r = (Uint8)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \ | ||||
| @@ -231,7 +241,7 @@ int SDL_SW_FillTriangle(SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Poin | ||||
|     Sint64 w0_row, w1_row, w2_row; | ||||
|     int bias_w0, bias_w1, bias_w2; | ||||
|  | ||||
|     int is_uniform; | ||||
|     SDL_bool is_uniform; | ||||
|  | ||||
|     SDL_Surface *tmp = NULL; | ||||
|  | ||||
| @@ -454,8 +464,10 @@ int SDL_SW_BlitTriangle( | ||||
|     SDL_Point *s0, SDL_Point *s1, SDL_Point *s2, | ||||
|     SDL_Surface *dst, | ||||
|     SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, | ||||
|     SDL_Color c0, SDL_Color c1, SDL_Color c2) | ||||
|     SDL_Color c0, SDL_Color c1, SDL_Color c2, | ||||
|     SDL_TextureAddressMode texture_address_mode) | ||||
| { | ||||
|     SDL_Surface *src_surface = src; | ||||
|     int ret = 0; | ||||
|     int src_locked = 0; | ||||
|     int dst_locked = 0; | ||||
| @@ -482,9 +494,9 @@ int SDL_SW_BlitTriangle( | ||||
|     Sint64 w0_row, w1_row, w2_row; | ||||
|     int bias_w0, bias_w1, bias_w2; | ||||
|  | ||||
|     int is_uniform; | ||||
|     SDL_bool is_uniform; | ||||
|  | ||||
|     int has_modulation; | ||||
|     SDL_bool has_modulation; | ||||
|  | ||||
|     if (!SDL_SurfaceValid(src)) { | ||||
|         return SDL_InvalidParamError("src"); | ||||
| @@ -527,7 +539,7 @@ int SDL_SW_BlitTriangle( | ||||
|     SDL_GetSurfaceBlendMode(src, &blend); | ||||
|  | ||||
|     /* TRIANGLE_GET_TEXTCOORD interpolates up to the max values included, so reduce by 1 */ | ||||
|     { | ||||
|     if (texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) { | ||||
|         SDL_Rect srcrect; | ||||
|         int maxx, maxy; | ||||
|         bounding_rect(s0, s1, s2, &srcrect); | ||||
| @@ -564,17 +576,6 @@ int SDL_SW_BlitTriangle( | ||||
|         has_modulation = SDL_TRUE; | ||||
|     } | ||||
|  | ||||
|     { | ||||
|         /* Clip triangle rect with surface rect */ | ||||
|         SDL_Rect rect; | ||||
|         rect.x = 0; | ||||
|         rect.y = 0; | ||||
|         rect.w = dst->w; | ||||
|         rect.h = dst->h; | ||||
|  | ||||
|         SDL_GetRectIntersection(&dstrect, &rect, &dstrect); | ||||
|     } | ||||
|  | ||||
|     { | ||||
|         /* Clip triangle with surface clip rect */ | ||||
|         SDL_Rect rect; | ||||
| @@ -695,6 +696,7 @@ int SDL_SW_BlitTriangle( | ||||
|         tmp_info.colorkey = info->colorkey; | ||||
|  | ||||
|         /* src */ | ||||
|         tmp_info.src_surface = src_surface; | ||||
|         tmp_info.src = (Uint8 *)src_ptr; | ||||
|         tmp_info.src_pitch = src_pitch; | ||||
|  | ||||
| @@ -714,7 +716,7 @@ int SDL_SW_BlitTriangle( | ||||
|         SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, (int)area, bias_w0, bias_w1, bias_w2, | ||||
|                               d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x, | ||||
|                               s2s0_x, s2s1_x, s2s0_y, s2s1_y, (int)w0_row, (int)w1_row, (int)w2_row, | ||||
|                               c0, c1, c2, is_uniform); | ||||
|                               c0, c1, c2, is_uniform, texture_address_mode); | ||||
|  | ||||
|         goto end; | ||||
|     } | ||||
| @@ -786,8 +788,9 @@ static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, | ||||
|                                   SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, | ||||
|                                   int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, | ||||
|                                   int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, | ||||
|                                   SDL_Color c0, SDL_Color c1, SDL_Color c2, int is_uniform) | ||||
|                                   SDL_Color c0, SDL_Color c1, SDL_Color c2, SDL_bool is_uniform, SDL_TextureAddressMode texture_address_mode) | ||||
| { | ||||
|     SDL_Surface *src_surface = info->src_surface; | ||||
|     const int flags = info->flags; | ||||
|     Uint32 modulateR = info->r; | ||||
|     Uint32 modulateG = info->g; | ||||
|   | ||||
| @@ -24,6 +24,8 @@ | ||||
|  | ||||
| #include "SDL_internal.h" | ||||
|  | ||||
| #include "../SDL_sysrender.h"   // For SDL_TextureAddressMode | ||||
|  | ||||
| extern int SDL_SW_FillTriangle(SDL_Surface *dst, | ||||
|                                SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, | ||||
|                                SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2); | ||||
| @@ -33,7 +35,8 @@ extern int SDL_SW_BlitTriangle( | ||||
|     SDL_Point *s0, SDL_Point *s1, SDL_Point *s2, | ||||
|     SDL_Surface *dst, | ||||
|     SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, | ||||
|     SDL_Color c0, SDL_Color c1, SDL_Color c2); | ||||
|     SDL_Color c0, SDL_Color c1, SDL_Color c2, | ||||
|     SDL_TextureAddressMode texture_address_mode); | ||||
|  | ||||
| extern void trianglepoint_2_fixedpoint(SDL_Point *a); | ||||
|  | ||||
|   | ||||
| @@ -158,9 +158,12 @@ typedef enum { | ||||
| } SDL_vulkan_renderpass_type; | ||||
|  | ||||
| /* Sampler types */ | ||||
| typedef enum { | ||||
|     SDL_VULKAN_SAMPLER_NEAREST = 0, | ||||
|     SDL_VULKAN_SAMPLER_LINEAR = 1, | ||||
| typedef enum | ||||
| { | ||||
|     SDL_VULKAN_SAMPLER_NEAREST_CLAMP, | ||||
|     SDL_VULKAN_SAMPLER_NEAREST_WRAP, | ||||
|     SDL_VULKAN_SAMPLER_LINEAR_CLAMP, | ||||
|     SDL_VULKAN_SAMPLER_LINEAR_WRAP, | ||||
|     SDL_VULKAN_NUM_SAMPLERS | ||||
| } SDL_vulkan_sampler_type; | ||||
|  | ||||
| @@ -181,6 +184,15 @@ static const float INPUTTYPE_SRGB = 1; | ||||
| static const float INPUTTYPE_SCRGB = 2; | ||||
| static const float INPUTTYPE_HDR10 = 3; | ||||
|  | ||||
| typedef enum | ||||
| { | ||||
|     SAMPLER_POINT_CLAMP, | ||||
|     SAMPLER_POINT_WRAP, | ||||
|     SAMPLER_LINEAR_CLAMP, | ||||
|     SAMPLER_LINEAR_WRAP, | ||||
|     NUM_SAMPLERS | ||||
| } Sampler; | ||||
|  | ||||
| /* Pixel shader constants, common values */ | ||||
| typedef struct | ||||
| { | ||||
| @@ -1904,34 +1916,37 @@ static VkResult VULKAN_CreateDeviceResources(SDL_Renderer *renderer, SDL_Propert | ||||
|  | ||||
|     /* Create samplers */ | ||||
|     { | ||||
|         static struct | ||||
|         { | ||||
|             VkFilter filter; | ||||
|             VkSamplerAddressMode address; | ||||
|         } samplerParams[] = { | ||||
|             { VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, | ||||
|             { VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT }, | ||||
|             { VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, | ||||
|             { VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT }, | ||||
|         }; | ||||
|         SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == SDL_VULKAN_NUM_SAMPLERS); | ||||
|         VkSamplerCreateInfo samplerCreateInfo = { 0 }; | ||||
|         samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; | ||||
|         samplerCreateInfo.magFilter = VK_FILTER_NEAREST; | ||||
|         samplerCreateInfo.minFilter = VK_FILTER_NEAREST; | ||||
|         samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; | ||||
|         samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||
|         samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||
|         samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||
|         samplerCreateInfo.mipLodBias = 0.0f; | ||||
|         samplerCreateInfo.anisotropyEnable = VK_FALSE; | ||||
|         samplerCreateInfo.maxAnisotropy = 1.0f; | ||||
|         samplerCreateInfo.minLod = 0.0f; | ||||
|         samplerCreateInfo.maxLod = 1000.0f; | ||||
|         result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &rendererData->samplers[SDL_VULKAN_SAMPLER_NEAREST]); | ||||
|         if (result != VK_SUCCESS) { | ||||
|             VULKAN_DestroyAll(renderer); | ||||
|             SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkCreateSampler(): %s\n", SDL_Vulkan_GetResultString(result)); | ||||
|             return result; | ||||
|         } | ||||
|  | ||||
|         samplerCreateInfo.magFilter = VK_FILTER_LINEAR; | ||||
|         samplerCreateInfo.minFilter = VK_FILTER_LINEAR; | ||||
|         samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; | ||||
|         result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &rendererData->samplers[SDL_VULKAN_SAMPLER_LINEAR]); | ||||
|         if (result != VK_SUCCESS) { | ||||
|             VULKAN_DestroyAll(renderer); | ||||
|             SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkCreateSampler(): %s\n", SDL_Vulkan_GetResultString(result)); | ||||
|             return result; | ||||
|         for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { | ||||
|             samplerCreateInfo.magFilter = samplerParams[i].filter; | ||||
|             samplerCreateInfo.minFilter = samplerParams[i].filter; | ||||
|             samplerCreateInfo.addressModeU = samplerParams[i].address; | ||||
|             samplerCreateInfo.addressModeV = samplerParams[i].address; | ||||
|             result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &rendererData->samplers[i]); | ||||
|             if (result != VK_SUCCESS) { | ||||
|                 VULKAN_DestroyAll(renderer); | ||||
|                 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "vkCreateSampler(): %s\n", SDL_Vulkan_GetResultString(result)); | ||||
|                 return result; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -2602,8 +2617,8 @@ static int VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD | ||||
|         samplerCreateInfo.magFilter = VK_FILTER_NEAREST; | ||||
|         samplerCreateInfo.minFilter = VK_FILTER_NEAREST; | ||||
|         samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; | ||||
|         samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||
|         samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||
|         samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; | ||||
|         samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; | ||||
|         samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; | ||||
|         samplerCreateInfo.mipLodBias = 0.0f; | ||||
|         samplerCreateInfo.anisotropyEnable = VK_FALSE; | ||||
| @@ -3627,10 +3642,28 @@ static SDL_bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderComm | ||||
|  | ||||
|     switch (textureData->scaleMode) { | ||||
|     case VK_FILTER_NEAREST: | ||||
|         textureSampler = rendererData->samplers[SDL_VULKAN_SAMPLER_NEAREST]; | ||||
|         switch (cmd->data.draw.texture_address_mode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             textureSampler = rendererData->samplers[SDL_VULKAN_SAMPLER_NEAREST_CLAMP]; | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             textureSampler = rendererData->samplers[SDL_VULKAN_SAMPLER_NEAREST_WRAP]; | ||||
|             break; | ||||
|         default: | ||||
|             return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|         } | ||||
|         break; | ||||
|     case VK_FILTER_LINEAR: | ||||
|         textureSampler = rendererData->samplers[SDL_VULKAN_SAMPLER_LINEAR]; | ||||
|         switch (cmd->data.draw.texture_address_mode) { | ||||
|         case SDL_TEXTURE_ADDRESS_CLAMP: | ||||
|             textureSampler = rendererData->samplers[SDL_VULKAN_SAMPLER_LINEAR_CLAMP]; | ||||
|             break; | ||||
|         case SDL_TEXTURE_ADDRESS_WRAP: | ||||
|             textureSampler = rendererData->samplers[SDL_VULKAN_SAMPLER_LINEAR_WRAP]; | ||||
|             break; | ||||
|         default: | ||||
|             return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode); | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -23,9 +23,10 @@ typedef struct SDLTest_SurfaceImage_s { | ||||
| } SDLTest_SurfaceImage_t; | ||||
|  | ||||
| /* Test images */ | ||||
| SDL_Surface *SDLTest_ImageBlit(void); | ||||
| SDL_Surface *SDLTest_ImageBlitColor(void); | ||||
| SDL_Surface *SDLTest_ImageFace(void); | ||||
| SDL_Surface *SDLTest_ImagePrimitives(void); | ||||
| SDL_Surface *SDLTest_ImageBlendingBackground(void); | ||||
| SDL_Surface *SDLTest_ImageBlendingSprite(void); | ||||
| extern SDL_Surface *SDLTest_ImageBlit(void); | ||||
| extern SDL_Surface *SDLTest_ImageBlitColor(void); | ||||
| extern SDL_Surface *SDLTest_ImageFace(void); | ||||
| extern SDL_Surface *SDLTest_ImagePrimitives(void); | ||||
| extern SDL_Surface *SDLTest_ImageBlendingBackground(void); | ||||
| extern SDL_Surface *SDLTest_ImageBlendingSprite(void); | ||||
| extern SDL_Surface *SDLTest_ImageWrappingSprite(void); | ||||
|   | ||||
| @@ -1076,6 +1076,109 @@ clearScreen(void) | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Tests geometry UV wrapping | ||||
|  */ | ||||
| static int render_testUVWrapping(void *arg) | ||||
| { | ||||
|     SDL_Vertex vertices[6]; | ||||
|     SDL_Vertex *verts = vertices; | ||||
|     SDL_FColor color = { 1.0f, 1.0f, 1.0f, 1.0f }; | ||||
|     float tw, th; | ||||
|     SDL_FRect rect; | ||||
|     float min_U = -0.5f; | ||||
|     float max_U = 1.5f; | ||||
|     float min_V = -0.5f; | ||||
|     float max_V = 1.5f; | ||||
|     SDL_Texture *tface; | ||||
|     SDL_Surface *referenceSurface = NULL; | ||||
|  | ||||
|     /* Clear surface. */ | ||||
|     clearScreen(); | ||||
|  | ||||
|     /* Create face surface. */ | ||||
|     tface = loadTestFace(); | ||||
|     SDLTest_AssertCheck(tface != NULL, "Verify loadTestFace() result"); | ||||
|     if (tface == NULL) { | ||||
|         return TEST_ABORTED; | ||||
|     } | ||||
|  | ||||
|     CHECK_FUNC(SDL_GetTextureSize, (tface, &tw, &th)) | ||||
|     rect.w = tw * 2; | ||||
|     rect.h = th * 2; | ||||
|     rect.x = (TESTRENDER_SCREEN_W - rect.w) / 2; | ||||
|     rect.y = (TESTRENDER_SCREEN_H - rect.h) / 2; | ||||
|  | ||||
|     /* | ||||
|      *   0--1 | ||||
|      *   | /| | ||||
|      *   |/ | | ||||
|      *   3--2 | ||||
|      * | ||||
|      *  Draw sprite2 as triangles that can be recombined as rect by software renderer | ||||
|      */ | ||||
|  | ||||
|     /* 0 */ | ||||
|     verts->position.x = rect.x; | ||||
|     verts->position.y = rect.y; | ||||
|     verts->color = color; | ||||
|     verts->tex_coord.x = min_U; | ||||
|     verts->tex_coord.y = min_V; | ||||
|     verts++; | ||||
|     /* 1 */ | ||||
|     verts->position.x = rect.x + rect.w; | ||||
|     verts->position.y = rect.y; | ||||
|     verts->color = color; | ||||
|     verts->tex_coord.x = max_U; | ||||
|     verts->tex_coord.y = min_V; | ||||
|     verts++; | ||||
|     /* 2 */ | ||||
|     verts->position.x = rect.x + rect.w; | ||||
|     verts->position.y = rect.y + rect.h; | ||||
|     verts->color = color; | ||||
|     verts->tex_coord.x = max_U; | ||||
|     verts->tex_coord.y = max_V; | ||||
|     verts++; | ||||
|     /* 0 */ | ||||
|     verts->position.x = rect.x; | ||||
|     verts->position.y = rect.y; | ||||
|     verts->color = color; | ||||
|     verts->tex_coord.x = min_U; | ||||
|     verts->tex_coord.y = min_V; | ||||
|     verts++; | ||||
|     /* 2 */ | ||||
|     verts->position.x = rect.x + rect.w; | ||||
|     verts->position.y = rect.y + rect.h; | ||||
|     verts->color = color; | ||||
|     verts->tex_coord.x = max_U; | ||||
|     verts->tex_coord.y = max_V; | ||||
|     verts++; | ||||
|     /* 3 */ | ||||
|     verts->position.x = rect.x; | ||||
|     verts->position.y = rect.y + rect.h; | ||||
|     verts->color = color; | ||||
|     verts->tex_coord.x = min_U; | ||||
|     verts->tex_coord.y = max_V; | ||||
|     verts++; | ||||
|  | ||||
|     /* Blit sprites as triangles onto the screen */ | ||||
|     SDL_RenderGeometry(renderer, tface, vertices, 6, NULL, 0); | ||||
|  | ||||
|     /* See if it's the same */ | ||||
|     referenceSurface = SDLTest_ImageWrappingSprite(); | ||||
|     compare(referenceSurface, ALLOWABLE_ERROR_OPAQUE); | ||||
|  | ||||
|     /* Make current */ | ||||
|     SDL_RenderPresent(renderer); | ||||
|  | ||||
|     /* Clean up. */ | ||||
|     SDL_DestroyTexture(tface); | ||||
|     SDL_DestroySurface(referenceSurface); | ||||
|     referenceSurface = NULL; | ||||
|  | ||||
|     return TEST_COMPLETED; | ||||
| } | ||||
|  | ||||
| /* ================= Test References ================== */ | ||||
|  | ||||
| /* Render test cases */ | ||||
| @@ -1115,11 +1218,15 @@ static const SDLTest_TestCaseReference renderTest9 = { | ||||
|     (SDLTest_TestCaseFp)render_testLogicalSize, "render_testLogicalSize", "Tests logical size", TEST_ENABLED | ||||
| }; | ||||
|  | ||||
| static const SDLTest_TestCaseReference renderTestUVWrapping = { | ||||
|     (SDLTest_TestCaseFp)render_testUVWrapping, "render_testUVWrapping", "Tests geometry UV wrapping", TEST_ENABLED | ||||
| }; | ||||
|  | ||||
| /* Sequence of Render test cases */ | ||||
| static const SDLTest_TestCaseReference *renderTests[] = { | ||||
|     &renderTest1, &renderTest2, &renderTest3, &renderTest4, | ||||
|     &renderTest5, &renderTest6, &renderTest7, &renderTest8, | ||||
|     &renderTest9, NULL | ||||
|     &renderTest9, &renderTestUVWrapping, NULL | ||||
| }; | ||||
|  | ||||
| /* Render test suite (global) */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Sam Lantinga
					Sam Lantinga