| /* |
| * Copyright 2016 Google Inc. All Rights Reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "glimp/gles/convert_pixel_data.h" |
| |
| #include "starboard/common/log.h" |
| #include "starboard/memory.h" |
| |
| namespace glimp { |
| namespace gles { |
| |
| namespace { |
| |
| // Helper method to properly copy pixel data from a source to destination |
| // pixel data, taking into account source and destination pitch. |
| void CopyPixelData(uint8_t* destination, |
| int destination_pitch, |
| const uint8_t* source, |
| int source_pitch, |
| int bytes_per_row, |
| int num_rows) { |
| if (destination_pitch == source_pitch) { |
| // If the pitches are equal, we can do the entire copy in one memcpy(). |
| memcpy(destination, source, destination_pitch * num_rows); |
| } else { |
| // If the pitches are not equal, we must memcpy each row separately. |
| for (int i = 0; i < num_rows; ++i) { |
| memcpy(destination + i * destination_pitch, source + i * source_pitch, |
| bytes_per_row); |
| } |
| } |
| } |
| |
| typedef void (*ConvertRowFunction)(int, uint8_t*, const uint8_t*, int); |
| |
| // Remaps input pixel channels such that 4-byte destination color values will |
| // have byte X set from source color value's channel_X_source byte. If |
| // any value for channel_X_source is set to -1, a 0 is instead set for that |
| // destination channel. |
| template <int channel_0_source, |
| int channel_1_source, |
| int channel_2_source, |
| int channel_3_source> |
| void RemapPixelChannels(int source_bytes_per_pixel, |
| uint8_t* destination, |
| const uint8_t* source, |
| int num_pixels) { |
| for (int i = 0; i < num_pixels; ++i) { |
| uint8_t channel_0 = channel_0_source == -1 ? 0 : source[channel_0_source]; |
| uint8_t channel_1 = channel_1_source == -1 ? 0 : source[channel_1_source]; |
| uint8_t channel_2 = channel_2_source == -1 ? 0 : source[channel_2_source]; |
| uint8_t channel_3 = channel_3_source == -1 ? 0 : source[channel_3_source]; |
| destination[0] = channel_0; |
| destination[1] = channel_1; |
| destination[2] = channel_2; |
| destination[3] = channel_3; |
| |
| destination += 4; |
| source += source_bytes_per_pixel; |
| } |
| } |
| |
| // Given a destination and source format, returns a function that will convert |
| // a row of pixels in a source buffer to a row of pixels in a destination |
| // buffer that contains a different format. This function may not implement |
| // every conversion, it is expected that conversion implementations will be |
| // added as they are needed. |
| ConvertRowFunction SelectConvertRowFunction(PixelFormat destination_format, |
| PixelFormat source_format) { |
| if (destination_format == source_format) { |
| return &RemapPixelChannels<0, 1, 2, 3>; |
| } else if (destination_format == kPixelFormatRGBA8 && |
| source_format == kPixelFormatARGB8) { |
| return &RemapPixelChannels<1, 2, 3, 0>; |
| } else if (destination_format == kPixelFormatRGBA8 && |
| source_format == kPixelFormatBGRA8) { |
| return &RemapPixelChannels<2, 1, 0, 3>; |
| } |
| |
| // Only what is currently needed by dependent libraries is supported, so |
| // feel free to add support for more pixel formats here as the need arises. |
| |
| return NULL; |
| } |
| |
| } // namespace |
| |
| void ConvertPixelDataInplace(uint8_t* pixels, |
| int pitch_in_bytes, |
| PixelFormat destination_format, |
| PixelFormat source_format, |
| int width, |
| int height) { |
| if (destination_format == source_format) { |
| return; |
| } |
| SB_DCHECK(BytesPerPixel(destination_format) == BytesPerPixel(source_format)); |
| // The destination format is different from the source format, so we must |
| // perform a conversion between pixels. |
| |
| // First select the function that will reformat the pixels, based on |
| // the destination and source pixel formats. |
| ConvertRowFunction convert_row_function = |
| SelectConvertRowFunction(destination_format, source_format); |
| SB_DCHECK(convert_row_function) |
| << "The requested pixel conversion is not yet implemented."; |
| |
| // Now, iterate through each row running the selected conversion function on |
| // each one. |
| uint8_t* pixel_row = pixels; |
| for (int row = 0; row < height; ++row) { |
| convert_row_function(BytesPerPixel(source_format), pixel_row, pixel_row, |
| width); |
| pixel_row += pitch_in_bytes; |
| } |
| } |
| |
| void ConvertPixelData(uint8_t* destination, |
| int destination_pitch_in_bytes, |
| PixelFormat destination_format, |
| const uint8_t* source, |
| int source_pitch_in_bytes, |
| PixelFormat source_format, |
| int width, |
| int height, |
| bool flip_y) { |
| if (destination_format == source_format && !flip_y) { |
| CopyPixelData(destination, destination_pitch_in_bytes, source, |
| source_pitch_in_bytes, BytesPerPixel(source_format) * width, |
| height); |
| } else { |
| // The destination format is different from the source format, so we must |
| // perform a conversion between pixels. |
| |
| // First select the function that will reformat the pixels, based on |
| // the destination and source pixel formats. |
| ConvertRowFunction convert_row_function = |
| SelectConvertRowFunction(destination_format, source_format); |
| SB_DCHECK(convert_row_function) |
| << "The requested pixel conversion is not yet implemented."; |
| |
| // Now, iterate through each row running the selected conversion function on |
| // each one. |
| for (int dest_row = 0; dest_row < height; ++dest_row) { |
| int source_row = flip_y ? height - dest_row - 1 : dest_row; |
| convert_row_function(BytesPerPixel(source_format), |
| destination + dest_row * destination_pitch_in_bytes, |
| source + source_row * source_pitch_in_bytes, width); |
| } |
| } |
| } |
| |
| } // namespace gles |
| } // namespace glimp |